summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDianne Hackborn <hackbod@google.com>2013-02-15 16:32:56 -0800
committerDianne Hackborn <hackbod@google.com>2013-02-19 12:08:58 -0800
commitc652de8141f5b8e3c6bcf8916842b6e106413b1a (patch)
treed3be73e9b665365bdacd01cfc66faa24054f5a9c
parent736ef1e9dedbdd0c24e27f170034f2f869fd083f (diff)
downloadframeworks_base-c652de8141f5b8e3c6bcf8916842b6e106413b1a.zip
frameworks_base-c652de8141f5b8e3c6bcf8916842b6e106413b1a.tar.gz
frameworks_base-c652de8141f5b8e3c6bcf8916842b6e106413b1a.tar.bz2
Implement display overscan support.
The window manager now keeps track of the overscan of each display, with an API to set it. The overscan impacts how it positions windows in the display. There is a new set of APIs for windows to say they would like to go into the overscan region. There is a call into the window manager to set the overscan region for a display, and it now has a concept of display settings that it stores presistently. Also added a new "wm" command, moving the window manager specific commands from the "am" command to there and adding a new now to set the overscan region. Change-Id: Id2c8092db64fd0a982274fedac7658d82f30f9ff
-rw-r--r--api/current.txt9
-rw-r--r--cmds/am/src/com/android/commands/am/Am.java90
-rw-r--r--cmds/wm/Android.mk28
-rw-r--r--cmds/wm/MODULE_LICENSE_APACHE20
-rw-r--r--cmds/wm/NOTICE190
-rw-r--r--cmds/wm/src/com/android/commands/wm/Wm.java241
-rwxr-xr-xcmds/wm/wm6
-rw-r--r--core/java/android/view/Display.java14
-rw-r--r--core/java/android/view/DisplayInfo.java101
-rw-r--r--core/java/android/view/IWindowManager.aidl2
-rw-r--r--core/java/android/view/WindowManager.java16
-rw-r--r--core/java/android/view/WindowManagerPolicy.java6
-rw-r--r--core/res/res/values/attrs.xml3
-rw-r--r--core/res/res/values/public.xml14
-rw-r--r--core/res/res/values/themes.xml43
-rw-r--r--core/res/res/values/themes_device_defaults.xml14
-rw-r--r--policy/src/com/android/internal/policy/impl/PhoneWindow.java12
-rw-r--r--policy/src/com/android/internal/policy/impl/PhoneWindowManager.java233
-rw-r--r--services/java/com/android/server/display/DisplayManagerService.java12
-rw-r--r--services/java/com/android/server/display/LogicalDisplay.java13
-rw-r--r--services/java/com/android/server/wm/DisplayContent.java5
-rw-r--r--services/java/com/android/server/wm/DisplaySettings.java224
-rw-r--r--services/java/com/android/server/wm/WindowManagerService.java92
23 files changed, 1156 insertions, 212 deletions
diff --git a/api/current.txt b/api/current.txt
index 50438e6..a6119b6 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -1174,6 +1174,7 @@ package android {
field public static final int windowMinWidthMinor = 16843607; // 0x1010357
field public static final int windowNoDisplay = 16843294; // 0x101021e
field public static final int windowNoTitle = 16842838; // 0x1010056
+ field public static final int windowOverscan = 16843727; // 0x10103cf
field public static final int windowShowAnimation = 16842934; // 0x10100b6
field public static final int windowShowWallpaper = 16843410; // 0x1010292
field public static final int windowSoftInputMode = 16843307; // 0x101022b
@@ -1693,6 +1694,7 @@ package android {
field public static final int Theme_Black = 16973832; // 0x1030008
field public static final int Theme_Black_NoTitleBar = 16973833; // 0x1030009
field public static final int Theme_Black_NoTitleBar_Fullscreen = 16973834; // 0x103000a
+ field public static final int Theme_Black_NoTitleBar_Overscan = 16974303; // 0x10301df
field public static final int Theme_DeviceDefault = 16974120; // 0x1030128
field public static final int Theme_DeviceDefault_Dialog = 16974126; // 0x103012e
field public static final int Theme_DeviceDefault_DialogWhenLarge = 16974134; // 0x1030136
@@ -1711,9 +1713,11 @@ package android {
field public static final int Theme_DeviceDefault_Light_Dialog_NoActionBar_MinWidth = 16974133; // 0x1030135
field public static final int Theme_DeviceDefault_Light_NoActionBar = 16974124; // 0x103012c
field public static final int Theme_DeviceDefault_Light_NoActionBar_Fullscreen = 16974125; // 0x103012d
+ field public static final int Theme_DeviceDefault_Light_NoActionBar_Overscan = 16974307; // 0x10301e3
field public static final int Theme_DeviceDefault_Light_Panel = 16974139; // 0x103013b
field public static final int Theme_DeviceDefault_NoActionBar = 16974121; // 0x1030129
field public static final int Theme_DeviceDefault_NoActionBar_Fullscreen = 16974122; // 0x103012a
+ field public static final int Theme_DeviceDefault_NoActionBar_Overscan = 16974306; // 0x10301e2
field public static final int Theme_DeviceDefault_Panel = 16974138; // 0x103013a
field public static final int Theme_DeviceDefault_Wallpaper = 16974140; // 0x103013c
field public static final int Theme_DeviceDefault_Wallpaper_NoTitleBar = 16974141; // 0x103013d
@@ -1736,9 +1740,11 @@ package android {
field public static final int Theme_Holo_Light_Dialog_NoActionBar_MinWidth = 16973942; // 0x1030076
field public static final int Theme_Holo_Light_NoActionBar = 16974064; // 0x10300f0
field public static final int Theme_Holo_Light_NoActionBar_Fullscreen = 16974065; // 0x10300f1
+ field public static final int Theme_Holo_Light_NoActionBar_Overscan = 16974305; // 0x10301e1
field public static final int Theme_Holo_Light_Panel = 16973948; // 0x103007c
field public static final int Theme_Holo_NoActionBar = 16973932; // 0x103006c
field public static final int Theme_Holo_NoActionBar_Fullscreen = 16973933; // 0x103006d
+ field public static final int Theme_Holo_NoActionBar_Overscan = 16974304; // 0x10301e0
field public static final int Theme_Holo_Panel = 16973947; // 0x103007b
field public static final int Theme_Holo_Wallpaper = 16973949; // 0x103007d
field public static final int Theme_Holo_Wallpaper_NoTitleBar = 16973950; // 0x103007e
@@ -1746,12 +1752,14 @@ package android {
field public static final int Theme_Light = 16973836; // 0x103000c
field public static final int Theme_Light_NoTitleBar = 16973837; // 0x103000d
field public static final int Theme_Light_NoTitleBar_Fullscreen = 16973838; // 0x103000e
+ field public static final int Theme_Light_NoTitleBar_Overscan = 16974302; // 0x10301de
field public static final int Theme_Light_Panel = 16973914; // 0x103005a
field public static final int Theme_Light_WallpaperSettings = 16973922; // 0x1030062
field public static final int Theme_NoDisplay = 16973909; // 0x1030055
field public static final int Theme_NoTitleBar = 16973830; // 0x1030006
field public static final int Theme_NoTitleBar_Fullscreen = 16973831; // 0x1030007
field public static final int Theme_NoTitleBar_OverlayActionModes = 16973930; // 0x103006a
+ field public static final int Theme_NoTitleBar_Overscan = 16974301; // 0x10301dd
field public static final int Theme_Panel = 16973913; // 0x1030059
field public static final int Theme_Translucent = 16973839; // 0x103000f
field public static final int Theme_Translucent_NoTitleBar = 16973840; // 0x1030010
@@ -26245,6 +26253,7 @@ package android.view {
field public static final int FLAG_IGNORE_CHEEK_PRESSES = 32768; // 0x8000
field public static final int FLAG_KEEP_SCREEN_ON = 128; // 0x80
field public static final int FLAG_LAYOUT_INSET_DECOR = 65536; // 0x10000
+ field public static final int FLAG_LAYOUT_IN_OVERSCAN = 33554432; // 0x2000000
field public static final int FLAG_LAYOUT_IN_SCREEN = 256; // 0x100
field public static final int FLAG_LAYOUT_NO_LIMITS = 512; // 0x200
field public static final int FLAG_NOT_FOCUSABLE = 8; // 0x8
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 3c1fbfe..9fa7dbb 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -26,7 +26,6 @@ import android.app.IInstrumentationWatcher;
import android.app.Instrumentation;
import android.app.UiAutomationConnection;
import android.content.ComponentName;
-import android.content.Context;
import android.content.IIntentReceiver;
import android.content.Intent;
import android.content.pm.IPackageManager;
@@ -39,7 +38,6 @@ import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.util.AndroidException;
-import android.view.Display;
import android.view.IWindowManager;
import java.io.BufferedReader;
@@ -134,10 +132,6 @@ public class Am {
runMonitor();
} else if (op.equals("screen-compat")) {
runScreenCompat();
- } else if (op.equals("display-size")) {
- runDisplaySize();
- } else if (op.equals("display-density")) {
- runDisplayDensity();
} else if (op.equals("to-uri")) {
runToUri(false);
} else if (op.equals("to-intent-uri")) {
@@ -1201,82 +1195,6 @@ public class Am {
} while (packageName != null);
}
- private void runDisplaySize() throws Exception {
- String size = nextArgRequired();
- int w, h;
- 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;
- }
- }
-
- IWindowManager wm = IWindowManager.Stub.asInterface(ServiceManager.checkService(
- Context.WINDOW_SERVICE));
- if (wm == null) {
- System.err.println(NO_SYSTEM_ERROR_CODE);
- throw new AndroidException("Can't connect to window manager; is the system running?");
- }
-
- try {
- if (w >= 0 && h >= 0) {
- // TODO(multidisplay): For now Configuration only applies to main screen.
- wm.setForcedDisplaySize(Display.DEFAULT_DISPLAY, w, h);
- } else {
- wm.clearForcedDisplaySize(Display.DEFAULT_DISPLAY);
- }
- } catch (RemoteException e) {
- }
- }
-
- private void runDisplayDensity() throws Exception {
- String densityStr = nextArgRequired();
- int density;
- 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;
- }
- }
-
- IWindowManager wm = IWindowManager.Stub.asInterface(ServiceManager.checkService(
- Context.WINDOW_SERVICE));
- if (wm == null) {
- System.err.println(NO_SYSTEM_ERROR_CODE);
- throw new AndroidException("Can't connect to window manager; is the system running?");
- }
-
- try {
- if (density > 0) {
- // TODO(multidisplay): For now Configuration only applies to main screen.
- wm.setForcedDisplayDensity(Display.DEFAULT_DISPLAY, density);
- } else {
- wm.clearForcedDisplayDensity(Display.DEFAULT_DISPLAY);
- }
- } catch (RemoteException e) {
- }
- }
-
private void runToUri(boolean intentScheme) throws Exception {
Intent intent = makeIntent(UserHandle.USER_CURRENT);
System.out.println(intent.toUri(intentScheme ? Intent.URI_INTENT_SCHEME : 0));
@@ -1454,8 +1372,6 @@ public class Am {
" am clear-debug-app\n" +
" am monitor [--gdb <port>]\n" +
" am screen-compat [on|off] <PACKAGE>\n" +
- " am display-size [reset|WxH]\n" +
- " am display-density [reset|DENSITY]\n" +
" am to-uri [INTENT]\n" +
" am to-intent-uri [INTENT]\n" +
" am switch-user <USER_ID>\n" +
@@ -1524,17 +1440,13 @@ public class Am {
"am clear-debug-app: clear the previously set-debug-app.\n" +
"\n" +
"am bug-report: request bug report generation; will launch UI\n" +
- " when done to select where it should be delivered." +
+ " when done to select where it should be delivered.\n" +
"\n" +
"am monitor: start monitoring for crashes or ANRs.\n" +
" --gdb: start gdbserv on the given port at crash/ANR\n" +
"\n" +
"am screen-compat: control screen compatibility mode of <PACKAGE>.\n" +
"\n" +
- "am display-size: override display size.\n" +
- "\n" +
- "am display-density: override display density.\n" +
- "\n" +
"am to-uri: print the given Intent specification as a URI.\n" +
"\n" +
"am to-intent-uri: print the given Intent specification as an intent: URI.\n" +
diff --git a/cmds/wm/Android.mk b/cmds/wm/Android.mk
new file mode 100644
index 0000000..a255cae
--- /dev/null
+++ b/cmds/wm/Android.mk
@@ -0,0 +1,28 @@
+# Copyright 2013 The Android Open Source Project
+#
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_MODULE := wm
+include $(BUILD_JAVA_LIBRARY)
+
+include $(CLEAR_VARS)
+
+NOTICE_FILE := NOTICE
+files_noticed := bin/wm
+
+# Generate rules for a single file. The argument is the file path relative to
+# the installation root
+define make-notice-file
+
+$(TARGET_OUT_NOTICE_FILES)/src/$(1).txt: $(LOCAL_PATH)/$(NOTICE_FILE)
+ @echo Notice file: $$< -- $$@
+ @mkdir -p $$(dir $$@)
+ @cat $$< >> $$@
+
+$(TARGET_OUT_NOTICE_FILES)/hash-timestamp: $(TARGET_OUT_NOTICE_FILES)/src/$(1).txt
+
+endef
+
+$(foreach file,$(files_noticed),$(eval $(call make-notice-file,$(file))))
diff --git a/cmds/wm/MODULE_LICENSE_APACHE2 b/cmds/wm/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/cmds/wm/MODULE_LICENSE_APACHE2
diff --git a/cmds/wm/NOTICE b/cmds/wm/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/cmds/wm/NOTICE
@@ -0,0 +1,190 @@
+
+ Copyright (c) 2005-2008, 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.
+
+ 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.
+
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
diff --git a/cmds/wm/src/com/android/commands/wm/Wm.java b/cmds/wm/src/com/android/commands/wm/Wm.java
new file mode 100644
index 0000000..f48764f
--- /dev/null
+++ b/cmds/wm/src/com/android/commands/wm/Wm.java
@@ -0,0 +1,241 @@
+/*
+**
+** Copyright 2013, 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 com.android.commands.wm;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.AndroidException;
+import android.view.Display;
+import android.view.IWindowManager;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class Wm {
+
+ private IWindowManager mWm;
+ private String[] mArgs;
+ private int mNextArg;
+ private String mCurArgData;
+
+ // These are magic strings understood by the Eclipse plugin.
+ private static final String FATAL_ERROR_CODE = "Error type 1";
+ private static final String NO_SYSTEM_ERROR_CODE = "Error type 2";
+ private static final String NO_CLASS_ERROR_CODE = "Error type 3";
+
+ /**
+ * Command-line entry point.
+ *
+ * @param args The command-line arguments
+ */
+ public static void main(String[] args) {
+ try {
+ (new Wm()).run(args);
+ } catch (IllegalArgumentException e) {
+ showUsage();
+ System.err.println("Error: " + e.getMessage());
+ } catch (Exception e) {
+ e.printStackTrace(System.err);
+ System.exit(1);
+ }
+ }
+
+ private void run(String[] args) throws Exception {
+ if (args.length < 1) {
+ showUsage();
+ return;
+ }
+
+ 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?");
+ }
+
+ mArgs = args;
+ String op = args[0];
+ mNextArg = 1;
+
+ if (op.equals("size")) {
+ runDisplaySize();
+ } else if (op.equals("density")) {
+ runDisplayDensity();
+ } else if (op.equals("overscan")) {
+ runDisplayOverscan();
+ } else {
+ throw new IllegalArgumentException("Unknown command: " + op);
+ }
+ }
+
+ private void runDisplaySize() throws Exception {
+ String size = nextArgRequired();
+ int w, h;
+ 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 = nextArgRequired();
+ int density;
+ 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) {
+ }
+ }
+
+ private void runDisplayOverscan() throws Exception {
+ String overscanStr = nextArgRequired();
+ Rect rect = new Rect();
+ int density;
+ if ("reset".equals(overscanStr)) {
+ rect.set(0, 0, 0, 0);
+ } else {
+ final Pattern FLATTENED_PATTERN = Pattern.compile(
+ "(-?\\d+),(-?\\d+),(-?\\d+),(-?\\d+)");
+ Matcher matcher = FLATTENED_PATTERN.matcher(overscanStr);
+ if (!matcher.matches()) {
+ System.err.println("Error: bad rectangle arg: " + overscanStr);
+ return;
+ }
+ rect.left = Integer.parseInt(matcher.group(1));
+ rect.top = Integer.parseInt(matcher.group(2));
+ rect.right = Integer.parseInt(matcher.group(3));
+ rect.bottom = Integer.parseInt(matcher.group(4));
+ }
+
+ try {
+ mWm.setOverscan(Display.DEFAULT_DISPLAY, rect.left, rect.top, rect.right, rect.bottom);
+ } catch (RemoteException e) {
+ }
+ }
+
+ private String nextOption() {
+ if (mCurArgData != null) {
+ String prev = mArgs[mNextArg - 1];
+ throw new IllegalArgumentException("No argument expected after \"" + prev + "\"");
+ }
+ if (mNextArg >= mArgs.length) {
+ return null;
+ }
+ String arg = mArgs[mNextArg];
+ if (!arg.startsWith("-")) {
+ return null;
+ }
+ mNextArg++;
+ if (arg.equals("--")) {
+ return null;
+ }
+ if (arg.length() > 1 && arg.charAt(1) != '-') {
+ if (arg.length() > 2) {
+ mCurArgData = arg.substring(2);
+ return arg.substring(0, 2);
+ } else {
+ mCurArgData = null;
+ return arg;
+ }
+ }
+ mCurArgData = null;
+ return arg;
+ }
+
+ private String nextArg() {
+ if (mCurArgData != null) {
+ String arg = mCurArgData;
+ mCurArgData = null;
+ return arg;
+ } else if (mNextArg < mArgs.length) {
+ return mArgs[mNextArg++];
+ } else {
+ return null;
+ }
+ }
+
+ private String nextArgRequired() {
+ String arg = nextArg();
+ if (arg == null) {
+ String prev = mArgs[mNextArg - 1];
+ throw new IllegalArgumentException("Argument expected after \"" + prev + "\"");
+ }
+ return arg;
+ }
+
+ private static void showUsage() {
+ System.err.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: override display size.\n" +
+ "\n" +
+ "wm density: override display density.\n" +
+ "\n" +
+ "wm overscan: set overscan area for display.\n"
+ );
+ }
+}
diff --git a/cmds/wm/wm b/cmds/wm/wm
new file mode 100755
index 0000000..f7a5bc7
--- /dev/null
+++ b/cmds/wm/wm
@@ -0,0 +1,6 @@
+# Script to start "wm" on the device, which has a very rudimentary
+# shell.
+#
+base=/system
+export CLASSPATH=$base/framework/wm.jar
+exec app_process $base/bin com.android.commands.wm.Wm "$@"
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 758abb5..e6a7950 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -437,6 +437,20 @@ public final class Display {
}
/**
+ * @hide
+ * Return a rectangle defining the insets of the overscan region of the display.
+ * Each field of the rectangle is the number of pixels the overscan area extends
+ * into the display on that side.
+ */
+ public void getOverscanInsets(Rect outRect) {
+ synchronized (this) {
+ updateDisplayInfoLocked();
+ outRect.set(mDisplayInfo.overscanLeft, mDisplayInfo.overscanTop,
+ mDisplayInfo.overscanRight, mDisplayInfo.overscanBottom);
+ }
+ }
+
+ /**
* Returns the rotation of the screen from its "natural" orientation.
* The returned value may be {@link Surface#ROTATION_0 Surface.ROTATION_0}
* (no rotation), {@link Surface#ROTATION_90 Surface.ROTATION_90},
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index 305fd5c..9fcd9b1 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -109,6 +109,30 @@ public final class DisplayInfo implements Parcelable {
public int logicalHeight;
/**
+ * @hide
+ * Number of overscan pixels on the left side of the display.
+ */
+ public int overscanLeft;
+
+ /**
+ * @hide
+ * Number of overscan pixels on the top side of the display.
+ */
+ public int overscanTop;
+
+ /**
+ * @hide
+ * Number of overscan pixels on the right side of the display.
+ */
+ public int overscanRight;
+
+ /**
+ * @hide
+ * Number of overscan pixels on the bottom side of the display.
+ */
+ public int overscanBottom;
+
+ /**
* The rotation of the display relative to its natural orientation.
* May be one of {@link android.view.Surface#ROTATION_0},
* {@link android.view.Surface#ROTATION_90}, {@link android.view.Surface#ROTATION_180},
@@ -196,6 +220,10 @@ public final class DisplayInfo implements Parcelable {
&& largestNominalAppHeight == other.largestNominalAppHeight
&& logicalWidth == other.logicalWidth
&& logicalHeight == other.logicalHeight
+ && overscanLeft == other.overscanLeft
+ && overscanTop == other.overscanTop
+ && overscanRight == other.overscanRight
+ && overscanBottom == other.overscanBottom
&& rotation == other.rotation
&& refreshRate == other.refreshRate
&& logicalDensityDpi == other.logicalDensityDpi
@@ -222,6 +250,10 @@ public final class DisplayInfo implements Parcelable {
largestNominalAppHeight = other.largestNominalAppHeight;
logicalWidth = other.logicalWidth;
logicalHeight = other.logicalHeight;
+ overscanLeft = other.overscanLeft;
+ overscanTop = other.overscanTop;
+ overscanRight = other.overscanRight;
+ overscanBottom = other.overscanBottom;
rotation = other.rotation;
refreshRate = other.refreshRate;
logicalDensityDpi = other.logicalDensityDpi;
@@ -243,6 +275,10 @@ public final class DisplayInfo implements Parcelable {
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();
@@ -265,6 +301,10 @@ public final class DisplayInfo implements Parcelable {
dest.writeInt(largestNominalAppHeight);
dest.writeInt(logicalWidth);
dest.writeInt(logicalHeight);
+ dest.writeInt(overscanLeft);
+ dest.writeInt(overscanTop);
+ dest.writeInt(overscanRight);
+ dest.writeInt(overscanBottom);
dest.writeInt(rotation);
dest.writeFloat(refreshRate);
dest.writeInt(logicalDensityDpi);
@@ -318,18 +358,55 @@ public final class DisplayInfo implements Parcelable {
// For debugging purposes
@Override
public String toString() {
- return "DisplayInfo{\"" + name + "\", app " + appWidth + " x " + appHeight
- + ", real " + logicalWidth + " x " + logicalHeight
- + ", largest app " + largestNominalAppWidth + " x " + largestNominalAppHeight
- + ", smallest app " + smallestNominalAppWidth + " x " + smallestNominalAppHeight
- + ", " + refreshRate + " fps"
- + ", rotation " + rotation
- + ", density " + logicalDensityDpi
- + ", " + physicalXDpi + " x " + physicalYDpi + " dpi"
- + ", layerStack " + layerStack
- + ", type " + Display.typeToString(type)
- + ", address " + address
- + flagsToString(flags) + "}";
+ StringBuilder sb = new StringBuilder();
+ sb.append("DisplayInfo{\"");
+ sb.append(name);
+ sb.append("\", app ");
+ sb.append(appWidth);
+ sb.append(" x ");
+ sb.append(appHeight);
+ sb.append(", real ");
+ sb.append(logicalWidth);
+ sb.append(" x ");
+ sb.append(logicalHeight);
+ if (overscanLeft != 0 || overscanTop != 0 || overscanRight != 0 || overscanBottom != 0) {
+ sb.append(", overscan (");
+ sb.append(overscanLeft);
+ sb.append(",");
+ sb.append(overscanTop);
+ sb.append(",");
+ sb.append(overscanRight);
+ sb.append(",");
+ sb.append(overscanBottom);
+ sb.append(")");
+ }
+ sb.append(", largest app ");
+ sb.append(largestNominalAppWidth);
+ sb.append(" x ");
+ sb.append(largestNominalAppHeight);
+ sb.append(", smallest app ");
+ sb.append(smallestNominalAppWidth);
+ sb.append(" x ");
+ sb.append(smallestNominalAppHeight);
+ sb.append(", ");
+ sb.append(refreshRate);
+ sb.append(" fps, rotation");
+ sb.append(rotation);
+ sb.append(", density ");
+ sb.append(logicalDensityDpi);
+ sb.append(" (");
+ sb.append(physicalXDpi);
+ sb.append(" x ");
+ sb.append(physicalYDpi);
+ sb.append(") dpi, layerStack ");
+ sb.append(layerStack);
+ sb.append(", type ");
+ sb.append(Display.typeToString(type));
+ sb.append(", address ");
+ sb.append(address);
+ sb.append(flagsToString(flags));
+ sb.append("}");
+ return sb.toString();
}
private static String flagsToString(int flags) {
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 885327c..e4ecb5c 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -65,6 +65,8 @@ interface IWindowManager
void setForcedDisplayDensity(int displayId, int density);
void clearForcedDisplayDensity(int displayId);
+ void setOverscan(int displayId, int left, int top, int right, int bottom);
+
// Is the device configured to have a full system bar for larger screens?
boolean hasSystemNavBar();
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 6a67d8b..d236561 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -735,20 +735,20 @@ public interface WindowManager extends ViewManager {
/**
* <p>Indicates whether this window should be hardware accelerated.
* Requesting hardware acceleration does not guarantee it will happen.</p>
- *
+ *
* <p>This flag can be controlled programmatically <em>only</em> to enable
* hardware acceleration. To enable hardware acceleration for a given
* window programmatically, do the following:</p>
- *
+ *
* <pre>
* Window w = activity.getWindow(); // in Activity's onCreate() for instance
* w.setFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
* WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
* </pre>
- *
+ *
* <p>It is important to remember that this flag <strong>must</strong>
* be set before setting the content view of your activity or dialog.</p>
- *
+ *
* <p>This flag cannot be used to disable hardware acceleration after it
* was enabled in your manifest using
* {@link android.R.attr#hardwareAccelerated}. If you need to selectively
@@ -756,13 +756,19 @@ public interface WindowManager extends ViewManager {
* for instance), make sure it is turned off in your manifest and enable it
* on your activity or dialog when you need it instead, using the method
* described above.</p>
- *
+ *
* <p>This flag is automatically set by the system if the
* {@link android.R.attr#hardwareAccelerated android:hardwareAccelerated}
* XML attribute is set to true on an activity or on the application.</p>
*/
public static final int FLAG_HARDWARE_ACCELERATED = 0x01000000;
+ /** Window flag: allow window contents to extend in to the screen's
+ * overscan area, if there is one. The window should still correctly
+ * position its contents to take the overscan area into account.
+ */
+ public static final int FLAG_LAYOUT_IN_OVERSCAN = 0x02000000;
+
// ----- HIDDEN FLAGS.
// These start at the high bit and go down.
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index b5d216a..192eded 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -458,6 +458,12 @@ public interface WindowManagerPolicy {
public void setInitialDisplaySize(Display display, int width, int height, int density);
/**
+ * Called by window manager to set the overscan region that should be used for the
+ * given display.
+ */
+ public void setDisplayOverscan(Display display, int left, int top, int right, int bottom);
+
+ /**
* Check permissions when adding a window.
*
* @param attrs The window's LayoutParams.
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index a3e5b2c..c73ff81 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -312,6 +312,8 @@
<attr name="windowNoTitle" format="boolean" />
<!-- Flag indicating whether this window should fill the entire screen. -->
<attr name="windowFullscreen" format="boolean" />
+ <!-- Flag indicating whether this window should extend into overscan region. -->
+ <attr name="windowOverscan" format="boolean" />
<!-- Flag indicating whether this is a floating window. -->
<attr name="windowIsFloating" format="boolean" />
<!-- Flag indicating whether this is a translucent window. -->
@@ -1562,6 +1564,7 @@
<attr name="windowFrame" />
<attr name="windowNoTitle" />
<attr name="windowFullscreen" />
+ <attr name="windowOverscan" />
<attr name="windowIsFloating" />
<attr name="windowIsTranslucent" />
<attr name="windowShowWallpaper" />
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 0d80082..42e5cf1 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2036,4 +2036,18 @@
<public type="attr" name="mipMap" id="0x010103cd" />
<public type="attr" name="mirrorForRtl" id="0x010103ce" />
+ <!-- ===============================================================
+ Resources added in version 19 of the platform
+ =============================================================== -->
+ <eat-comment />
+
+ <public type="attr" name="windowOverscan" />
+ <public type="style" name="Theme.NoTitleBar.Overscan" />
+ <public type="style" name="Theme.Light.NoTitleBar.Overscan" />
+ <public type="style" name="Theme.Black.NoTitleBar.Overscan" />
+ <public type="style" name="Theme.Holo.NoActionBar.Overscan" />
+ <public type="style" name="Theme.Holo.Light.NoActionBar.Overscan" />
+ <public type="style" name="Theme.DeviceDefault.NoActionBar.Overscan" />
+ <public type="style" name="Theme.DeviceDefault.Light.NoActionBar.Overscan" />
+
</resources>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 75850dd..411419b 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -166,6 +166,7 @@ please see themes_device_defaults.xml.
<item name="windowFrame">@null</item>
<item name="windowNoTitle">false</item>
<item name="windowFullscreen">false</item>
+ <item name="windowOverscan">false</item>
<item name="windowIsFloating">false</item>
<item name="windowContentOverlay">@null</item>
<item name="windowShowWallpaper">false</item>
@@ -403,6 +404,14 @@ please see themes_device_defaults.xml.
<item name="android:windowContentOverlay">@null</item>
</style>
+ <!-- Variant of {@link #Theme} that has no title bar and no status bar and extending
+ into the display overscan region. -->
+ <style name="Theme.NoTitleBar.Overscan">
+ <item name="android:windowFullscreen">true</item>
+ <item name="android:windowOverscan">true</item>
+ <item name="android:windowContentOverlay">@null</item>
+ </style>
+
<!-- Theme for a light background with dark text on top. Set your activity
to this theme if you would like such an appearance. As with the
default theme, you should try to assume little more than that the
@@ -495,6 +504,14 @@ please see themes_device_defaults.xml.
<item name="android:windowContentOverlay">@null</item>
</style>
+ <!-- Variant of {@link #Theme_Light} that has no title bar and
+ no status bar and extending into the display overscan region. -->
+ <style name="Theme.Light.NoTitleBar.Overscan">
+ <item name="android:windowFullscreen">true</item>
+ <item name="android:windowOverscan">true</item>
+ <item name="android:windowContentOverlay">@null</item>
+ </style>
+
<!-- Variant on {@link #Theme} that ensures the background is
completely black. This is useful for things like image viewers and
media players. If you want the normal (dark background) theme
@@ -516,6 +533,14 @@ please see themes_device_defaults.xml.
<item name="android:windowContentOverlay">@null</item>
</style>
+ <!-- Variant of {@link #Theme_Black} that has no title bar and
+ no status bar and extending into the display overscan region. -->
+ <style name="Theme.Black.NoTitleBar.Overscan">
+ <item name="android:windowFullscreen">true</item>
+ <item name="android:windowOverscan">true</item>
+ <item name="android:windowContentOverlay">@null</item>
+ </style>
+
<!-- Theme for windows that want to have the user's selected
wallpaper appear behind them (for API level 10 and lower). -->
<style name="Theme.Wallpaper">
@@ -1010,6 +1035,7 @@ please see themes_device_defaults.xml.
<item name="windowFrame">@null</item>
<item name="windowNoTitle">false</item>
<item name="windowFullscreen">false</item>
+ <item name="windowOverscan">false</item>
<item name="windowIsFloating">false</item>
<item name="windowContentOverlay">@null</item>
<item name="windowShowWallpaper">false</item>
@@ -1324,6 +1350,7 @@ please see themes_device_defaults.xml.
<item name="windowFrame">@null</item>
<item name="windowNoTitle">false</item>
<item name="windowFullscreen">false</item>
+ <item name="windowOverscan">false</item>
<item name="windowIsFloating">false</item>
<item name="android:windowContentOverlay">@android:drawable/ab_solid_shadow_holo</item>
<item name="windowShowWallpaper">false</item>
@@ -1563,6 +1590,14 @@ please see themes_device_defaults.xml.
<item name="android:windowContentOverlay">@null</item>
</style>
+ <!-- Variant of the holographic (dark) theme that has no title bar and fills
+ the entire screen and extends into the display overscan region. -->
+ <style name="Theme.Holo.NoActionBar.Overscan">
+ <item name="android:windowFullscreen">true</item>
+ <item name="android:windowOverscan">true</item>
+ <item name="android:windowContentOverlay">@null</item>
+ </style>
+
<!-- Variant of the holographic (light) theme with no action bar. -->
<style name="Theme.Holo.Light.NoActionBar">
<item name="android:windowActionBar">false</item>
@@ -1576,6 +1611,14 @@ please see themes_device_defaults.xml.
<item name="android:windowContentOverlay">@null</item>
</style>
+ <!-- Variant of the holographic (light) theme that has no title bar and fills
+ the entire screen and extends into the display overscan region. -->
+ <style name="Theme.Holo.Light.NoActionBar.Overscan">
+ <item name="android:windowFullscreen">true</item>
+ <item name="android:windowOverscan">true</item>
+ <item name="android:windowContentOverlay">@null</item>
+ </style>
+
<!-- Dialog themes for Holo -->
<eat-comment />
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index 4178cc4..71aa5e6 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -202,12 +202,17 @@ easier.
<!-- Variant of {@link #Theme_DeviceDefault} with no action bar -->
<style name="Theme.DeviceDefault.NoActionBar" parent="Theme.Holo.NoActionBar" >
-
</style>
+
<!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar -->
<style name="Theme.DeviceDefault.NoActionBar.Fullscreen" parent="Theme.Holo.NoActionBar.Fullscreen" >
+ </style>
+ <!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar and
+ extending in to overscan region. -->
+ <style name="Theme.DeviceDefault.NoActionBar.Overscan" parent="Theme.Holo.NoActionBar.Overscan" >
</style>
+
<!-- Variant of {@link #Theme_DeviceDefault} with a light-colored style -->
<style name="Theme.DeviceDefault.Light" parent="Theme.Holo.Light" >
<!-- Text styles -->
@@ -356,11 +361,14 @@ easier.
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar -->
<style name="Theme.DeviceDefault.Light.NoActionBar" parent="Theme.Holo.Light.NoActionBar" >
-
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar -->
<style name="Theme.DeviceDefault.Light.NoActionBar.Fullscreen" parent="Theme.Holo.Light.NoActionBar.Fullscreen" >
-
+ </style>
+ <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar
+ and extending in to overscan region-->
+ <style name="Theme.DeviceDefault.Light.NoActionBar.Overscan"
+ parent="Theme.Holo.Light.NoActionBar.Overscan" >
</style>
<!-- DeviceDefault theme for dialog windows and activities. This changes the window to be
floating (not fill the entire screen), and puts a frame around its contents. You can set this
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 88a0ef3..e1d9b73 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -20,11 +20,7 @@ import static android.view.View.MeasureSpec.EXACTLY;
import static android.view.View.MeasureSpec.getMode;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
-import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
-import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
+import static android.view.WindowManager.LayoutParams.*;
import com.android.internal.view.RootViewSurfaceTaker;
import com.android.internal.view.StandaloneActionMode;
@@ -2639,7 +2635,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
}
if (a.getBoolean(com.android.internal.R.styleable.Window_windowFullscreen, false)) {
- setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN&(~getForcedWindowFlags()));
+ setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN & (~getForcedWindowFlags()));
+ }
+
+ if (a.getBoolean(com.android.internal.R.styleable.Window_windowOverscan, false)) {
+ setFlags(FLAG_LAYOUT_IN_OVERSCAN, FLAG_LAYOUT_IN_OVERSCAN&(~getForcedWindowFlags()));
}
if (a.getBoolean(com.android.internal.R.styleable.Window_windowShowWallpaper, false)) {
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 9cb54a9..4e5825e 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -101,55 +101,7 @@ import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
-import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
-import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON;
-import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
-import static android.view.WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN;
-import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
-import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
-import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
-import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
-import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
-import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL;
-import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS;
-import static android.view.WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_DRAG;
-import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
-import static android.view.WindowManager.LayoutParams.TYPE_HIDDEN_NAV_CONSUMER;
-import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
-import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD;
-import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
-import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
-import static android.view.WindowManager.LayoutParams.TYPE_PHONE;
-import static android.view.WindowManager.LayoutParams.TYPE_POINTER;
-import static android.view.WindowManager.LayoutParams.TYPE_PRIORITY_PHONE;
-import static android.view.WindowManager.LayoutParams.TYPE_RECENTS_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_SEARCH_BAR;
-import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
-import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
-import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
-import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
-import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
-import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
-import static android.view.WindowManager.LayoutParams.TYPE_UNIVERSE_BACKGROUND;
-import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static android.view.WindowManager.LayoutParams.*;
import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT;
import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_OPEN;
import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_CLOSED;
@@ -353,8 +305,12 @@ public class PhoneWindowManager implements WindowManagerPolicy {
PointerLocationView mPointerLocationView;
InputChannel mPointerLocationInputChannel;
- // The current size of the screen; really; (ir)regardless of whether the status
- // bar can be hidden or not
+ // The current size of the screen; really; extends into the overscan area of
+ // the screen and doesn't account for any system elements like the status bar.
+ int mOverscanScreenLeft, mOverscanScreenTop;
+ int mOverscanScreenWidth, mOverscanScreenHeight;
+ // The current visible size of the screen; really; (ir)regardless of whether the status
+ // bar can be hidden but not extending into the overscan area.
int mUnrestrictedScreenLeft, mUnrestrictedScreenTop;
int mUnrestrictedScreenWidth, mUnrestrictedScreenHeight;
// The current size of the screen; these may be different than (0,0)-(dw,dh)
@@ -455,6 +411,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
int mPortraitRotation = 0; // default portrait rotation
int mUpsideDownRotation = 0; // "other" portrait rotation
+ int mOverscanLeft = 0;
+ int mOverscanTop = 0;
+ int mOverscanRight = 0;
+ int mOverscanBottom = 0;
+
// What we do when the user long presses on home
private int mLongPressOnHomeBehavior = -1;
@@ -946,6 +907,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
@Override
public void setInitialDisplaySize(Display display, int width, int height, int density) {
+ if (display.getDisplayId() != Display.DEFAULT_DISPLAY) {
+ throw new IllegalArgumentException("Can only set the default display");
+ }
mDisplay = display;
int shortSize, longSize;
@@ -1056,6 +1020,16 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mHdmiRotationLock = SystemProperties.getBoolean("persist.demo.hdmirotationlock", false);
}
+ @Override
+ public void setDisplayOverscan(Display display, int left, int top, int right, int bottom) {
+ if (display.getDisplayId() == Display.DEFAULT_DISPLAY) {
+ mOverscanLeft = left;
+ mOverscanTop = top;
+ mOverscanRight = right;
+ mOverscanBottom = bottom;
+ }
+ }
+
public void updateSettings() {
ContentResolver resolver = mContext.getContentResolver();
boolean updateRotation = false;
@@ -2388,7 +2362,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
contentInset.set(mStableLeft, mStableTop,
availRight - mStableRight, availBottom - mStableBottom);
}
- } else if ((fl & FLAG_FULLSCREEN) != 0) {
+ } else if ((fl & FLAG_FULLSCREEN) != 0 || (fl & FLAG_LAYOUT_IN_OVERSCAN) != 0) {
contentInset.setEmpty();
} else if ((systemUiVisibility & (View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)) == 0) {
@@ -2407,20 +2381,64 @@ public class PhoneWindowManager implements WindowManagerPolicy {
@Override
public void beginLayoutLw(boolean isDefaultDisplay, int displayWidth, int displayHeight,
int displayRotation) {
- mUnrestrictedScreenLeft = mUnrestrictedScreenTop = 0;
- mUnrestrictedScreenWidth = displayWidth;
- mUnrestrictedScreenHeight = displayHeight;
- mRestrictedScreenLeft = mRestrictedScreenTop = 0;
- mRestrictedScreenWidth = displayWidth;
- mRestrictedScreenHeight = displayHeight;
+ final int overscanLeft, overscanTop, overscanRight, overscanBottom;
+ if (isDefaultDisplay) {
+ switch (displayRotation) {
+ case Surface.ROTATION_90:
+ overscanLeft = mOverscanTop;
+ overscanTop = mOverscanRight;
+ overscanRight = mOverscanBottom;
+ overscanBottom = mOverscanLeft;
+ break;
+ case Surface.ROTATION_180:
+ overscanLeft = mOverscanRight;
+ overscanTop = mOverscanBottom;
+ overscanRight = mOverscanLeft;
+ overscanBottom = mOverscanTop;
+ break;
+ case Surface.ROTATION_270:
+ overscanLeft = mOverscanBottom;
+ overscanTop = mOverscanLeft;
+ overscanRight = mOverscanTop;
+ overscanBottom = mOverscanRight;
+ break;
+ default:
+ overscanLeft = mOverscanLeft;
+ overscanTop = mOverscanTop;
+ overscanRight = mOverscanRight;
+ overscanBottom = mOverscanBottom;
+ break;
+ }
+ } else {
+ overscanLeft = 0;
+ overscanTop = 0;
+ overscanRight = 0;
+ overscanBottom = 0;
+ }
+ mOverscanScreenLeft = 0;
+ mOverscanScreenTop = 0;
+ mOverscanScreenWidth = displayWidth;
+ mOverscanScreenHeight = displayHeight;
+ mSystemLeft = 0;
+ mSystemTop = 0;
+ mSystemRight = displayWidth;
+ mSystemBottom = displayHeight;
+ mUnrestrictedScreenLeft = overscanLeft;
+ mUnrestrictedScreenTop = overscanTop;
+ mUnrestrictedScreenWidth = displayWidth - overscanLeft - overscanRight;
+ mUnrestrictedScreenHeight = displayHeight - overscanTop - overscanBottom;
+ mRestrictedScreenLeft = mUnrestrictedScreenLeft;
+ mRestrictedScreenTop = mUnrestrictedScreenTop;
+ mRestrictedScreenWidth = mUnrestrictedScreenWidth;
+ mRestrictedScreenHeight = mUnrestrictedScreenHeight;
mDockLeft = mContentLeft = mStableLeft = mStableFullscreenLeft
- = mSystemLeft = mCurLeft = 0;
+ = mCurLeft = mUnrestrictedScreenLeft;
mDockTop = mContentTop = mStableTop = mStableFullscreenTop
- = mSystemTop = mCurTop = 0;
+ = mCurTop = mUnrestrictedScreenTop;
mDockRight = mContentRight = mStableRight = mStableFullscreenRight
- = mSystemRight = mCurRight = displayWidth;
+ = mCurRight = displayWidth - overscanRight;
mDockBottom = mContentBottom = mStableBottom = mStableFullscreenBottom
- = mSystemBottom = mCurBottom = displayHeight;
+ = mCurBottom = displayHeight - overscanBottom;
mDockLayer = 0x10000000;
mStatusBarLayer = -1;
@@ -2467,8 +2485,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mNavigationBarOnBottom = (!mNavigationBarCanMove || displayWidth < displayHeight);
if (mNavigationBarOnBottom) {
// It's a system nav bar or a portrait screen; nav bar goes on bottom.
- int top = displayHeight - mNavigationBarHeightForRotation[displayRotation];
- mTmpNavigationFrame.set(0, top, displayWidth, displayHeight);
+ int top = displayHeight - overscanBottom
+ - mNavigationBarHeightForRotation[displayRotation];
+ mTmpNavigationFrame.set(0, top, displayWidth, displayHeight - overscanBottom);
mStableBottom = mStableFullscreenBottom = mTmpNavigationFrame.top;
if (navVisible) {
mNavigationBar.showLw(true);
@@ -2486,8 +2505,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
} else {
// Landscape screen; nav bar goes to the right.
- int left = displayWidth - mNavigationBarWidthForRotation[displayRotation];
- mTmpNavigationFrame.set(left, 0, displayWidth, displayHeight);
+ int left = displayWidth - overscanRight
+ - mNavigationBarWidthForRotation[displayRotation];
+ mTmpNavigationFrame.set(left, 0, displayWidth - overscanRight, displayHeight);
mStableRight = mStableFullscreenRight = mTmpNavigationFrame.left;
if (navVisible) {
mNavigationBar.showLw(true);
@@ -2524,8 +2544,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// apply any navigation bar insets
pf.left = df.left = mUnrestrictedScreenLeft;
pf.top = df.top = mUnrestrictedScreenTop;
- pf.right = df.right = mUnrestrictedScreenWidth - mUnrestrictedScreenLeft;
- pf.bottom = df.bottom = mUnrestrictedScreenHeight - mUnrestrictedScreenTop;
+ pf.right = df.right = mUnrestrictedScreenWidth + mUnrestrictedScreenLeft;
+ pf.bottom = df.bottom = mUnrestrictedScreenHeight + mUnrestrictedScreenTop;
vf.left = mStableLeft;
vf.top = mStableTop;
vf.right = mStableRight;
@@ -2685,12 +2705,12 @@ public class PhoneWindowManager implements WindowManagerPolicy {
setAttachedWindowFrames(win, fl, adjust, attached, true, pf, df, cf, vf);
} else {
// Give the window full screen.
- pf.left = df.left = cf.left = mUnrestrictedScreenLeft;
- pf.top = df.top = cf.top = mUnrestrictedScreenTop;
+ pf.left = df.left = cf.left = mOverscanScreenLeft;
+ pf.top = df.top = cf.top = mOverscanScreenTop;
pf.right = df.right = cf.right
- = mUnrestrictedScreenLeft + mUnrestrictedScreenWidth;
+ = mOverscanScreenLeft + mOverscanScreenWidth;
pf.bottom = df.bottom = cf.bottom
- = mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
+ = mOverscanScreenTop + mOverscanScreenHeight;
}
} else if (attrs.type == TYPE_INPUT_METHOD) {
pf.left = df.left = cf.left = vf.left = mDockLeft;
@@ -2729,28 +2749,37 @@ public class PhoneWindowManager implements WindowManagerPolicy {
pf.top = df.top = mUnrestrictedScreenTop;
pf.right = df.right = hasNavBar
? mRestrictedScreenLeft+mRestrictedScreenWidth
- : mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
+ : mUnrestrictedScreenLeft + mUnrestrictedScreenWidth;
pf.bottom = df.bottom = hasNavBar
? mRestrictedScreenTop+mRestrictedScreenHeight
- : mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
+ : mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
if (DEBUG_LAYOUT) {
Log.v(TAG, String.format(
"Laying out status bar window: (%d,%d - %d,%d)",
pf.left, pf.top, pf.right, pf.bottom));
}
+ } else if ((attrs.flags&FLAG_LAYOUT_IN_OVERSCAN) != 0
+ && attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
+ && attrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
+ // Asking to layout into the overscan region, so give it that pure
+ // unrestricted area.
+ pf.left = df.left = mOverscanScreenLeft;
+ pf.top = df.top = mOverscanScreenTop;
+ pf.right = df.right = mOverscanScreenLeft + mOverscanScreenWidth;
+ pf.bottom = df.bottom = mOverscanScreenTop + mOverscanScreenHeight;
} else if (mCanHideNavigationBar
&& (sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
&& attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
&& attrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
// Asking for layout as if the nav bar is hidden, lets the
- // application extend into the unrestricted screen area. We
+ // application extend into the unrestricted overscan screen area. We
// only do this for application windows to ensure no window that
// can be above the nav bar can do this.
pf.left = df.left = mUnrestrictedScreenLeft;
pf.top = df.top = mUnrestrictedScreenTop;
- pf.right = df.right = mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
- pf.bottom = df.bottom = mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
+ pf.right = df.right = mUnrestrictedScreenLeft + mUnrestrictedScreenWidth;
+ pf.bottom = df.bottom = mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
} else {
pf.left = df.left = mRestrictedScreenLeft;
pf.top = df.top = mRestrictedScreenTop;
@@ -2793,10 +2822,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
pf.top = df.top = cf.top = mUnrestrictedScreenTop;
pf.right = df.right = cf.right = hasNavBar
? mRestrictedScreenLeft+mRestrictedScreenWidth
- : mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
+ : mUnrestrictedScreenLeft + mUnrestrictedScreenWidth;
pf.bottom = df.bottom = cf.bottom = hasNavBar
? mRestrictedScreenTop+mRestrictedScreenHeight
- : mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
+ : mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
if (DEBUG_LAYOUT) {
Log.v(TAG, String.format(
"Laying out IN_SCREEN status bar window: (%d,%d - %d,%d)",
@@ -2807,8 +2836,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// The navigation bar has Real Ultimate Power.
pf.left = df.left = mUnrestrictedScreenLeft;
pf.top = df.top = mUnrestrictedScreenTop;
- pf.right = df.right = mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
- pf.bottom = df.bottom = mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
+ pf.right = df.right = mUnrestrictedScreenLeft + mUnrestrictedScreenWidth;
+ pf.bottom = df.bottom = mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
if (DEBUG_LAYOUT) {
Log.v(TAG, String.format(
"Laying out navigation bar window: (%d,%d - %d,%d)",
@@ -2818,18 +2847,29 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|| attrs.type == TYPE_BOOT_PROGRESS)
&& ((fl & FLAG_FULLSCREEN) != 0)) {
// Fullscreen secure system overlays get what they ask for.
- pf.left = df.left = mUnrestrictedScreenLeft;
- pf.top = df.top = mUnrestrictedScreenTop;
- pf.right = df.right = mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
- pf.bottom = df.bottom = mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
+ pf.left = df.left = mOverscanScreenLeft;
+ pf.top = df.top = mOverscanScreenTop;
+ pf.right = df.right = mOverscanScreenLeft + mOverscanScreenWidth;
+ pf.bottom = df.bottom = mOverscanScreenTop + mOverscanScreenHeight;
} else if (attrs.type == TYPE_BOOT_PROGRESS
|| attrs.type == TYPE_UNIVERSE_BACKGROUND) {
// Boot progress screen always covers entire display.
- pf.left = df.left = cf.left = mUnrestrictedScreenLeft;
- pf.top = df.top = cf.top = mUnrestrictedScreenTop;
- pf.right = df.right = cf.right = mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
+ pf.left = df.left = cf.left = mOverscanScreenLeft;
+ pf.top = df.top = cf.top = mOverscanScreenTop;
+ pf.right = df.right = cf.right = mOverscanScreenLeft + mOverscanScreenWidth;
+ pf.bottom = df.bottom = cf.bottom
+ = mOverscanScreenTop + mOverscanScreenHeight;
+ } else if ((attrs.flags & FLAG_LAYOUT_IN_OVERSCAN) != 0
+ && attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
+ && attrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
+ // Asking to layout into the overscan region, so give it that pure
+ // unrestricted area.
+ pf.left = df.left = cf.left = mOverscanScreenLeft;
+ pf.top = df.top = cf.top = mOverscanScreenTop;
+ pf.right = df.right = cf.right
+ = mOverscanScreenLeft + mOverscanScreenWidth;
pf.bottom = df.bottom = cf.bottom
- = mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
+ = mOverscanScreenTop + mOverscanScreenHeight;
} else if (mCanHideNavigationBar
&& (sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
&& attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
@@ -2843,9 +2883,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// what the screen would be if only laying out to hide the nav bar.
pf.left = df.left = cf.left = mUnrestrictedScreenLeft;
pf.top = df.top = cf.top = mUnrestrictedScreenTop;
- pf.right = df.right = cf.right = mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
+ pf.right = df.right = cf.right = mUnrestrictedScreenLeft + mUnrestrictedScreenWidth;
pf.bottom = df.bottom = cf.bottom
- = mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
+ = mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
} else {
pf.left = df.left = cf.left = mRestrictedScreenLeft;
pf.top = df.top = cf.top = mRestrictedScreenTop;
@@ -4661,6 +4701,17 @@ public class PhoneWindowManager implements WindowManagerPolicy {
pw.print(prefix); pw.print("mScreenOnEarly="); pw.print(mScreenOnEarly);
pw.print(" mScreenOnFully="); pw.print(mScreenOnFully);
pw.print(" mOrientationSensorEnabled="); pw.println(mOrientationSensorEnabled);
+ pw.print(prefix); pw.print("mOverscanScreen=("); pw.print(mOverscanScreenLeft);
+ pw.print(","); pw.print(mOverscanScreenTop);
+ pw.print(") "); pw.print(mOverscanScreenWidth);
+ pw.print("x"); pw.println(mOverscanScreenHeight);
+ if (mOverscanLeft != 0 || mOverscanTop != 0
+ || mOverscanRight != 0 || mOverscanBottom != 0) {
+ pw.print(prefix); pw.print("mOverscan left="); pw.print(mOverscanLeft);
+ pw.print(" top="); pw.print(mOverscanTop);
+ pw.print(" right="); pw.print(mOverscanRight);
+ pw.print(" bottom="); pw.println(mOverscanBottom);
+ }
pw.print(prefix); pw.print("mUnrestrictedScreen=("); pw.print(mUnrestrictedScreenLeft);
pw.print(","); pw.print(mUnrestrictedScreenTop);
pw.print(") "); pw.print(mUnrestrictedScreenWidth);
diff --git a/services/java/com/android/server/display/DisplayManagerService.java b/services/java/com/android/server/display/DisplayManagerService.java
index 813c9c7..17b0662 100644
--- a/services/java/com/android/server/display/DisplayManagerService.java
+++ b/services/java/com/android/server/display/DisplayManagerService.java
@@ -324,6 +324,18 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
}
/**
+ * Sets the overscan insets for a particular display.
+ */
+ public void setOverscan(int displayId, int left, int top, int right, int bottom) {
+ synchronized (mSyncRoot) {
+ LogicalDisplay display = mLogicalDisplays.get(displayId);
+ if (display != null) {
+ display.setOverscan(left, top, right, bottom);
+ }
+ }
+ }
+
+ /**
* Called by the window manager to perform traversals while holding a
* surface flinger transaction.
*/
diff --git a/services/java/com/android/server/display/LogicalDisplay.java b/services/java/com/android/server/display/LogicalDisplay.java
index 1583137..424ec36 100644
--- a/services/java/com/android/server/display/LogicalDisplay.java
+++ b/services/java/com/android/server/display/LogicalDisplay.java
@@ -143,6 +143,19 @@ final class LogicalDisplay {
}
}
+ public void setOverscan(int left, int top, int right, int bottom) {
+ mInfo.overscanLeft = left;
+ mInfo.overscanTop = top;
+ mInfo.overscanRight = right;
+ mInfo.overscanBottom = bottom;
+ if (mOverrideDisplayInfo != null) {
+ mOverrideDisplayInfo.overscanLeft = left;
+ mOverrideDisplayInfo.overscanTop = top;
+ mOverrideDisplayInfo.overscanRight = right;
+ mOverrideDisplayInfo.overscanBottom = bottom;
+ }
+ }
+
/**
* Returns true if the logical display is in a valid state.
* This method should be checked after calling {@link #updateLocked} to handle the
diff --git a/services/java/com/android/server/wm/DisplayContent.java b/services/java/com/android/server/wm/DisplayContent.java
index 89e0f17..cc7c8b0 100644
--- a/services/java/com/android/server/wm/DisplayContent.java
+++ b/services/java/com/android/server/wm/DisplayContent.java
@@ -19,6 +19,9 @@ package com.android.server.wm;
import static com.android.server.wm.WindowManagerService.FORWARD_ITERATOR;
import static com.android.server.wm.WindowManagerService.REVERSE_ITERATOR;
+import android.graphics.Rect;
+import android.os.Debug;
+import android.util.Slog;
import android.util.SparseArray;
import android.view.Display;
import android.view.DisplayInfo;
@@ -316,6 +319,7 @@ class DisplayContent {
pw.print("x"); pw.print(mDisplayInfo.smallestNominalAppHeight);
pw.print("-"); pw.print(mDisplayInfo.largestNominalAppWidth);
pw.print("x"); pw.println(mDisplayInfo.largestNominalAppHeight);
+ pw.print(subPrefix); pw.print("layoutNeeded="); pw.println(layoutNeeded);
AppTokenIterator iterator = getTmpAppIterator(REVERSE_ITERATOR);
int ndx = iterator.size() - 1;
if (ndx >= 0) {
@@ -360,7 +364,6 @@ class DisplayContent {
pw.println();
}
}
- pw.print(subPrefix); pw.print("layoutNeeded="); pw.println(layoutNeeded);
pw.println();
}
}
diff --git a/services/java/com/android/server/wm/DisplaySettings.java b/services/java/com/android/server/wm/DisplaySettings.java
new file mode 100644
index 0000000..34d1a64
--- /dev/null
+++ b/services/java/com/android/server/wm/DisplaySettings.java
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2013 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 com.android.server.wm;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.os.Environment;
+import android.util.AtomicFile;
+import android.util.Slog;
+import android.util.Xml;
+import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.XmlUtils;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.HashMap;
+
+/**
+ * Current persistent settings about a display
+ */
+public class DisplaySettings {
+ private static final String TAG = WindowManagerService.TAG;
+
+ private final Context mContext;
+ private final AtomicFile mFile;
+ private final HashMap<String, Entry> mEntries = new HashMap<String, Entry>();
+
+ public static class Entry {
+ public final String name;
+ public int overscanLeft;
+ public int overscanTop;
+ public int overscanRight;
+ public int overscanBottom;
+
+ public Entry(String _name) {
+ name = _name;
+ }
+ }
+
+ public DisplaySettings(Context context) {
+ mContext = context;
+ File dataDir = Environment.getDataDirectory();
+ File systemDir = new File(dataDir, "system");
+ mFile = new AtomicFile(new File(systemDir, "display_settings.xml"));
+ }
+
+ public void getOverscanLocked(String name, Rect outRect) {
+ Entry entry = mEntries.get(name);
+ if (entry != null) {
+ outRect.left = entry.overscanLeft;
+ outRect.top = entry.overscanTop;
+ outRect.right = entry.overscanRight;
+ outRect.bottom = entry.overscanBottom;
+ } else {
+ outRect.set(0, 0, 0, 0);
+ }
+ }
+
+ public void setOverscanLocked(String name, int left, int top, int right, int bottom) {
+ if (left == 0 && top == 0 && right == 0 && bottom == 0) {
+ // Right now all we are storing is overscan; if there is no overscan,
+ // we have no need for the entry.
+ mEntries.remove(name);
+ return;
+ }
+ Entry entry = mEntries.get(name);
+ if (entry == null) {
+ entry = new Entry(name);
+ mEntries.put(name, entry);
+ }
+ entry.overscanLeft = left;
+ entry.overscanTop = top;
+ entry.overscanRight = right;
+ entry.overscanBottom = bottom;
+ }
+
+ public void readSettingsLocked() {
+ FileInputStream stream;
+ try {
+ stream = mFile.openRead();
+ } catch (FileNotFoundException e) {
+ Slog.i(TAG, "No existing display settings " + mFile.getBaseFile()
+ + "; starting empty");
+ return;
+ }
+ boolean success = false;
+ try {
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(stream, null);
+ int type;
+ while ((type = parser.next()) != XmlPullParser.START_TAG
+ && type != XmlPullParser.END_DOCUMENT) {
+ ;
+ }
+
+ if (type != XmlPullParser.START_TAG) {
+ throw new IllegalStateException("no start tag found");
+ }
+
+ int outerDepth = parser.getDepth();
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals("display")) {
+ readDisplay(parser);
+ } else {
+ Slog.w(TAG, "Unknown element under <display-settings>: "
+ + parser.getName());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+ success = true;
+ } catch (IllegalStateException e) {
+ Slog.w(TAG, "Failed parsing " + e);
+ } catch (NullPointerException e) {
+ Slog.w(TAG, "Failed parsing " + e);
+ } catch (NumberFormatException e) {
+ Slog.w(TAG, "Failed parsing " + e);
+ } catch (XmlPullParserException e) {
+ Slog.w(TAG, "Failed parsing " + e);
+ } catch (IOException e) {
+ Slog.w(TAG, "Failed parsing " + e);
+ } catch (IndexOutOfBoundsException e) {
+ Slog.w(TAG, "Failed parsing " + e);
+ } finally {
+ if (!success) {
+ mEntries.clear();
+ }
+ try {
+ stream.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+
+ private int getIntAttribute(XmlPullParser parser, String name) {
+ try {
+ String str = parser.getAttributeValue(null, name);
+ return str != null ? Integer.parseInt(str) : 0;
+ } catch (NumberFormatException e) {
+ return 0;
+ }
+ }
+
+ private void readDisplay(XmlPullParser parser) throws NumberFormatException,
+ XmlPullParserException, IOException {
+ String name = parser.getAttributeValue(null, "name");
+ if (name != null) {
+ Entry entry = new Entry(name);
+ entry.overscanLeft = getIntAttribute(parser, "overscanLeft");
+ entry.overscanTop = getIntAttribute(parser, "overscanTop");
+ entry.overscanRight = getIntAttribute(parser, "overscanRight");
+ entry.overscanBottom = getIntAttribute(parser, "overscanBottom");
+ mEntries.put(name, entry);
+ }
+ XmlUtils.skipCurrentTag(parser);
+ }
+
+ public void writeSettingsLocked() {
+ FileOutputStream stream;
+ try {
+ stream = mFile.startWrite();
+ } catch (IOException e) {
+ Slog.w(TAG, "Failed to write display settings: " + e);
+ return;
+ }
+
+ try {
+ XmlSerializer out = new FastXmlSerializer();
+ out.setOutput(stream, "utf-8");
+ out.startDocument(null, true);
+ out.startTag(null, "display-settings");
+
+ for (Entry entry : mEntries.values()) {
+ out.startTag(null, "display");
+ out.attribute(null, "name", entry.name);
+ if (entry.overscanLeft != 0) {
+ out.attribute(null, "overscanLeft", Integer.toString(entry.overscanLeft));
+ }
+ if (entry.overscanTop != 0) {
+ out.attribute(null, "overscanTop", Integer.toString(entry.overscanTop));
+ }
+ if (entry.overscanRight != 0) {
+ out.attribute(null, "overscanRight", Integer.toString(entry.overscanRight));
+ }
+ if (entry.overscanBottom != 0) {
+ out.attribute(null, "overscanBottom", Integer.toString(entry.overscanBottom));
+ }
+ out.endTag(null, "display");
+ }
+
+ out.endTag(null, "display-settings");
+ out.endDocument();
+ mFile.finishWrite(stream);
+ } catch (IOException e) {
+ Slog.w(TAG, "Failed to write display settings, restoring backup.", e);
+ mFile.failWrite(stream);
+ }
+ }
+}
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index d38273d..b7637b9 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -320,6 +320,8 @@ public class WindowManagerService extends IWindowManager.Stub
final AppOpsManager mAppOps;
+ final DisplaySettings mDisplaySettings;
+
/**
* All currently active sessions with clients.
*/
@@ -731,6 +733,8 @@ public class WindowManagerService extends IWindowManager.Stub
com.android.internal.R.bool.config_sf_limitedAlpha);
mDisplayManagerService = displayManager;
mHeadless = displayManager.isHeadless();
+ mDisplaySettings = new DisplaySettings(context);
+ mDisplaySettings.readSettingsLocked();
mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
mDisplayManager.registerDisplayListener(this, null);
@@ -7089,6 +7093,15 @@ public class WindowManagerService extends IWindowManager.Stub
@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.
@@ -7160,6 +7173,15 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public void clearForcedDisplaySize(int displayId) {
+ 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) {
@@ -7173,6 +7195,15 @@ public class WindowManagerService extends IWindowManager.Stub
@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) {
@@ -7195,6 +7226,15 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public void clearForcedDisplayDensity(int displayId) {
+ 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) {
@@ -7233,6 +7273,33 @@ public class WindowManagerService extends IWindowManager.Stub
performLayoutAndPlaceSurfacesLocked();
}
+ public void setOverscan(int displayId, int left, int top, int right, int bottom) {
+ if (mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
+ PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Must hold permission " +
+ android.Manifest.permission.WRITE_SECURE_SETTINGS);
+ }
+ synchronized(mWindowMap) {
+ DisplayContent displayContent = getDisplayContentLocked(displayId);
+ if (displayContent != null) {
+ mDisplayManagerService.setOverscan(displayId, left, top, right, bottom);
+ final DisplayInfo displayInfo = displayContent.getDisplayInfo();
+ synchronized(displayContent.mDisplaySizeLock) {
+ displayInfo.overscanLeft = left;
+ displayInfo.overscanTop = top;
+ displayInfo.overscanRight = right;
+ displayInfo.overscanBottom = bottom;
+ }
+ mPolicy.setDisplayOverscan(displayContent.getDisplay(), left, top, right, bottom);
+ displayContent.layoutNeeded = true;
+ mDisplaySettings.setOverscanLocked(displayInfo.name, left, top, right, bottom);
+ mDisplaySettings.writeSettingsLocked();
+ performLayoutAndPlaceSurfacesLocked();
+ }
+ }
+ }
+
@Override
public boolean hasSystemNavBar() {
return mPolicy.hasSystemNavBar();
@@ -9694,7 +9761,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (dumpAll) {
pw.print(" mSystemDecorRect="); pw.print(mSystemDecorRect.toShortString());
pw.print(" mSystemDecorLayer="); pw.print(mSystemDecorLayer);
- pw.print(" mScreenRecr="); pw.println(mScreenRect.toShortString());
+ pw.print(" mScreenRect="); pw.println(mScreenRect.toShortString());
if (mLastStatusBarVisibility != 0) {
pw.print(" mLastStatusBarVisibility=0x");
pw.println(Integer.toHexString(mLastStatusBarVisibility));
@@ -9973,12 +10040,28 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
+ 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;
+ }
+
public void createDisplayContentLocked(final Display display) {
if (display == null) {
throw new IllegalArgumentException("getDisplayContent: display must not be null");
}
- final DisplayContent displayContent = new DisplayContent(display);
- mDisplayContents.put(display.getDisplayId(), displayContent);
+ newDisplayContentLocked(display);
}
/**
@@ -9992,8 +10075,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (displayContent == null) {
final Display display = mDisplayManager.getDisplay(displayId);
if (display != null) {
- displayContent = new DisplayContent(display);
- mDisplayContents.put(displayId, displayContent);
+ displayContent = newDisplayContentLocked(display);
}
}
return displayContent;