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.util.HashMap;
36 
37 /**
38  * Current persistent settings about a display
39  */
40 public class DisplaySettings {
41     private static final String TAG = WindowManagerService.TAG;
42 
43     private final AtomicFile mFile;
44     private final HashMap<String, Entry> mEntries = new HashMap<String, Entry>();
45 
46     public static class Entry {
47         public final String name;
48         public int overscanLeft;
49         public int overscanTop;
50         public int overscanRight;
51         public int overscanBottom;
52 
Entry(String _name)53         public Entry(String _name) {
54             name = _name;
55         }
56     }
57 
DisplaySettings()58     public DisplaySettings() {
59         File dataDir = Environment.getDataDirectory();
60         File systemDir = new File(dataDir, "system");
61         mFile = new AtomicFile(new File(systemDir, "display_settings.xml"));
62     }
63 
getOverscanLocked(String name, String uniqueId, Rect outRect)64     public void getOverscanLocked(String name, String uniqueId, Rect outRect) {
65         // Try to get the entry with the unique if possible.
66         // Else, fall back on the display name.
67         Entry entry;
68         if (uniqueId == null || (entry = mEntries.get(uniqueId)) == null) {
69             entry = mEntries.get(name);
70         }
71         if (entry != null) {
72             outRect.left = entry.overscanLeft;
73             outRect.top = entry.overscanTop;
74             outRect.right = entry.overscanRight;
75             outRect.bottom = entry.overscanBottom;
76         } else {
77             outRect.set(0, 0, 0, 0);
78         }
79     }
80 
setOverscanLocked(String name, int left, int top, int right, int bottom)81     public void setOverscanLocked(String name, int left, int top, int right, int bottom) {
82         if (left == 0 && top == 0 && right == 0 && bottom == 0) {
83             // Right now all we are storing is overscan; if there is no overscan,
84             // we have no need for the entry.
85             mEntries.remove(name);
86             return;
87         }
88         Entry entry = mEntries.get(name);
89         if (entry == null) {
90             entry = new Entry(name);
91             mEntries.put(name, entry);
92         }
93         entry.overscanLeft = left;
94         entry.overscanTop = top;
95         entry.overscanRight = right;
96         entry.overscanBottom = bottom;
97     }
98 
readSettingsLocked()99     public void readSettingsLocked() {
100         FileInputStream stream;
101         try {
102             stream = mFile.openRead();
103         } catch (FileNotFoundException e) {
104             Slog.i(TAG, "No existing display settings " + mFile.getBaseFile()
105                     + "; starting empty");
106             return;
107         }
108         boolean success = false;
109         try {
110             XmlPullParser parser = Xml.newPullParser();
111             parser.setInput(stream, null);
112             int type;
113             while ((type = parser.next()) != XmlPullParser.START_TAG
114                     && type != XmlPullParser.END_DOCUMENT) {
115                 // Do nothing.
116             }
117 
118             if (type != XmlPullParser.START_TAG) {
119                 throw new IllegalStateException("no start tag found");
120             }
121 
122             int outerDepth = parser.getDepth();
123             while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
124                     && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
125                 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
126                     continue;
127                 }
128 
129                 String tagName = parser.getName();
130                 if (tagName.equals("display")) {
131                     readDisplay(parser);
132                 } else {
133                     Slog.w(TAG, "Unknown element under <display-settings>: "
134                             + parser.getName());
135                     XmlUtils.skipCurrentTag(parser);
136                 }
137             }
138             success = true;
139         } catch (IllegalStateException e) {
140             Slog.w(TAG, "Failed parsing " + e);
141         } catch (NullPointerException e) {
142             Slog.w(TAG, "Failed parsing " + e);
143         } catch (NumberFormatException e) {
144             Slog.w(TAG, "Failed parsing " + e);
145         } catch (XmlPullParserException e) {
146             Slog.w(TAG, "Failed parsing " + e);
147         } catch (IOException e) {
148             Slog.w(TAG, "Failed parsing " + e);
149         } catch (IndexOutOfBoundsException e) {
150             Slog.w(TAG, "Failed parsing " + e);
151         } finally {
152             if (!success) {
153                 mEntries.clear();
154             }
155             try {
156                 stream.close();
157             } catch (IOException e) {
158             }
159         }
160     }
161 
getIntAttribute(XmlPullParser parser, String name)162     private int getIntAttribute(XmlPullParser parser, String name) {
163         try {
164             String str = parser.getAttributeValue(null, name);
165             return str != null ? Integer.parseInt(str) : 0;
166         } catch (NumberFormatException e) {
167             return 0;
168         }
169     }
170 
readDisplay(XmlPullParser parser)171     private void readDisplay(XmlPullParser parser) throws NumberFormatException,
172             XmlPullParserException, IOException {
173         String name = parser.getAttributeValue(null, "name");
174         if (name != null) {
175             Entry entry = new Entry(name);
176             entry.overscanLeft = getIntAttribute(parser, "overscanLeft");
177             entry.overscanTop = getIntAttribute(parser, "overscanTop");
178             entry.overscanRight = getIntAttribute(parser, "overscanRight");
179             entry.overscanBottom = getIntAttribute(parser, "overscanBottom");
180             mEntries.put(name, entry);
181         }
182         XmlUtils.skipCurrentTag(parser);
183     }
184 
writeSettingsLocked()185     public void writeSettingsLocked() {
186         FileOutputStream stream;
187         try {
188             stream = mFile.startWrite();
189         } catch (IOException e) {
190             Slog.w(TAG, "Failed to write display settings: " + e);
191             return;
192         }
193 
194         try {
195             XmlSerializer out = new FastXmlSerializer();
196             out.setOutput(stream, "utf-8");
197             out.startDocument(null, true);
198             out.startTag(null, "display-settings");
199 
200             for (Entry entry : mEntries.values()) {
201                 out.startTag(null, "display");
202                 out.attribute(null, "name", entry.name);
203                 if (entry.overscanLeft != 0) {
204                     out.attribute(null, "overscanLeft", Integer.toString(entry.overscanLeft));
205                 }
206                 if (entry.overscanTop != 0) {
207                     out.attribute(null, "overscanTop", Integer.toString(entry.overscanTop));
208                 }
209                 if (entry.overscanRight != 0) {
210                     out.attribute(null, "overscanRight", Integer.toString(entry.overscanRight));
211                 }
212                 if (entry.overscanBottom != 0) {
213                     out.attribute(null, "overscanBottom", Integer.toString(entry.overscanBottom));
214                 }
215                 out.endTag(null, "display");
216             }
217 
218             out.endTag(null, "display-settings");
219             out.endDocument();
220             mFile.finishWrite(stream);
221         } catch (IOException e) {
222             Slog.w(TAG, "Failed to write display settings, restoring backup.", e);
223             mFile.failWrite(stream);
224         }
225     }
226 }
227