summaryrefslogtreecommitdiffstats
path: root/services
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 /services
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
Diffstat (limited to 'services')
-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
5 files changed, 340 insertions, 6 deletions
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;