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