diff options
Diffstat (limited to 'services/java/com/android/server')
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; |