1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.wm; 18 19 import android.graphics.Rect; 20 import android.os.Environment; 21 import android.util.AtomicFile; 22 import android.util.Slog; 23 import android.util.Xml; 24 import com.android.internal.util.FastXmlSerializer; 25 import com.android.internal.util.XmlUtils; 26 import org.xmlpull.v1.XmlPullParser; 27 import org.xmlpull.v1.XmlPullParserException; 28 import org.xmlpull.v1.XmlSerializer; 29 30 import java.io.File; 31 import java.io.FileInputStream; 32 import java.io.FileNotFoundException; 33 import java.io.FileOutputStream; 34 import java.io.IOException; 35 import java.nio.charset.StandardCharsets; 36 import java.util.HashMap; 37 38 /** 39 * Current persistent settings about a display 40 */ 41 public class DisplaySettings { 42 private static final String TAG = WindowManagerService.TAG; 43 44 private final AtomicFile mFile; 45 private final HashMap<String, Entry> mEntries = new HashMap<String, Entry>(); 46 47 public static class Entry { 48 public final String name; 49 public int overscanLeft; 50 public int overscanTop; 51 public int overscanRight; 52 public int overscanBottom; 53 Entry(String _name)54 public Entry(String _name) { 55 name = _name; 56 } 57 } 58 DisplaySettings()59 public DisplaySettings() { 60 File dataDir = Environment.getDataDirectory(); 61 File systemDir = new File(dataDir, "system"); 62 mFile = new AtomicFile(new File(systemDir, "display_settings.xml")); 63 } 64 getOverscanLocked(String name, String uniqueId, Rect outRect)65 public void getOverscanLocked(String name, String uniqueId, Rect outRect) { 66 // Try to get the entry with the unique if possible. 67 // Else, fall back on the display name. 68 Entry entry; 69 if (uniqueId == null || (entry = mEntries.get(uniqueId)) == null) { 70 entry = mEntries.get(name); 71 } 72 if (entry != null) { 73 outRect.left = entry.overscanLeft; 74 outRect.top = entry.overscanTop; 75 outRect.right = entry.overscanRight; 76 outRect.bottom = entry.overscanBottom; 77 } else { 78 outRect.set(0, 0, 0, 0); 79 } 80 } 81 setOverscanLocked(String name, int left, int top, int right, int bottom)82 public void setOverscanLocked(String name, int left, int top, int right, int bottom) { 83 if (left == 0 && top == 0 && right == 0 && bottom == 0) { 84 // Right now all we are storing is overscan; if there is no overscan, 85 // we have no need for the entry. 86 mEntries.remove(name); 87 return; 88 } 89 Entry entry = mEntries.get(name); 90 if (entry == null) { 91 entry = new Entry(name); 92 mEntries.put(name, entry); 93 } 94 entry.overscanLeft = left; 95 entry.overscanTop = top; 96 entry.overscanRight = right; 97 entry.overscanBottom = bottom; 98 } 99 readSettingsLocked()100 public void readSettingsLocked() { 101 FileInputStream stream; 102 try { 103 stream = mFile.openRead(); 104 } catch (FileNotFoundException e) { 105 Slog.i(TAG, "No existing display settings " + mFile.getBaseFile() 106 + "; starting empty"); 107 return; 108 } 109 boolean success = false; 110 try { 111 XmlPullParser parser = Xml.newPullParser(); 112 parser.setInput(stream, StandardCharsets.UTF_8.name()); 113 int type; 114 while ((type = parser.next()) != XmlPullParser.START_TAG 115 && type != XmlPullParser.END_DOCUMENT) { 116 // Do nothing. 117 } 118 119 if (type != XmlPullParser.START_TAG) { 120 throw new IllegalStateException("no start tag found"); 121 } 122 123 int outerDepth = parser.getDepth(); 124 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 125 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 126 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 127 continue; 128 } 129 130 String tagName = parser.getName(); 131 if (tagName.equals("display")) { 132 readDisplay(parser); 133 } else { 134 Slog.w(TAG, "Unknown element under <display-settings>: " 135 + parser.getName()); 136 XmlUtils.skipCurrentTag(parser); 137 } 138 } 139 success = true; 140 } catch (IllegalStateException e) { 141 Slog.w(TAG, "Failed parsing " + e); 142 } catch (NullPointerException e) { 143 Slog.w(TAG, "Failed parsing " + e); 144 } catch (NumberFormatException e) { 145 Slog.w(TAG, "Failed parsing " + e); 146 } catch (XmlPullParserException e) { 147 Slog.w(TAG, "Failed parsing " + e); 148 } catch (IOException e) { 149 Slog.w(TAG, "Failed parsing " + e); 150 } catch (IndexOutOfBoundsException e) { 151 Slog.w(TAG, "Failed parsing " + e); 152 } finally { 153 if (!success) { 154 mEntries.clear(); 155 } 156 try { 157 stream.close(); 158 } catch (IOException e) { 159 } 160 } 161 } 162 getIntAttribute(XmlPullParser parser, String name)163 private int getIntAttribute(XmlPullParser parser, String name) { 164 try { 165 String str = parser.getAttributeValue(null, name); 166 return str != null ? Integer.parseInt(str) : 0; 167 } catch (NumberFormatException e) { 168 return 0; 169 } 170 } 171 readDisplay(XmlPullParser parser)172 private void readDisplay(XmlPullParser parser) throws NumberFormatException, 173 XmlPullParserException, IOException { 174 String name = parser.getAttributeValue(null, "name"); 175 if (name != null) { 176 Entry entry = new Entry(name); 177 entry.overscanLeft = getIntAttribute(parser, "overscanLeft"); 178 entry.overscanTop = getIntAttribute(parser, "overscanTop"); 179 entry.overscanRight = getIntAttribute(parser, "overscanRight"); 180 entry.overscanBottom = getIntAttribute(parser, "overscanBottom"); 181 mEntries.put(name, entry); 182 } 183 XmlUtils.skipCurrentTag(parser); 184 } 185 writeSettingsLocked()186 public void writeSettingsLocked() { 187 FileOutputStream stream; 188 try { 189 stream = mFile.startWrite(); 190 } catch (IOException e) { 191 Slog.w(TAG, "Failed to write display settings: " + e); 192 return; 193 } 194 195 try { 196 XmlSerializer out = new FastXmlSerializer(); 197 out.setOutput(stream, StandardCharsets.UTF_8.name()); 198 out.startDocument(null, true); 199 out.startTag(null, "display-settings"); 200 201 for (Entry entry : mEntries.values()) { 202 out.startTag(null, "display"); 203 out.attribute(null, "name", entry.name); 204 if (entry.overscanLeft != 0) { 205 out.attribute(null, "overscanLeft", Integer.toString(entry.overscanLeft)); 206 } 207 if (entry.overscanTop != 0) { 208 out.attribute(null, "overscanTop", Integer.toString(entry.overscanTop)); 209 } 210 if (entry.overscanRight != 0) { 211 out.attribute(null, "overscanRight", Integer.toString(entry.overscanRight)); 212 } 213 if (entry.overscanBottom != 0) { 214 out.attribute(null, "overscanBottom", Integer.toString(entry.overscanBottom)); 215 } 216 out.endTag(null, "display"); 217 } 218 219 out.endTag(null, "display-settings"); 220 out.endDocument(); 221 mFile.finishWrite(stream); 222 } catch (IOException e) { 223 Slog.w(TAG, "Failed to write display settings, restoring backup.", e); 224 mFile.failWrite(stream); 225 } 226 } 227 } 228