• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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.display;
18 
19 import android.hardware.devicestate.DeviceStateManager;
20 import android.os.Environment;
21 import android.util.IndentingPrintWriter;
22 import android.util.Slog;
23 import android.util.SparseArray;
24 import android.view.DisplayAddress;
25 
26 import com.android.server.display.config.layout.Layouts;
27 import com.android.server.display.config.layout.XmlParser;
28 import com.android.server.display.layout.Layout;
29 
30 import org.xmlpull.v1.XmlPullParserException;
31 
32 import java.io.BufferedInputStream;
33 import java.io.File;
34 import java.io.FileInputStream;
35 import java.io.IOException;
36 import java.io.InputStream;
37 
38 import javax.xml.datatype.DatatypeConfigurationException;
39 
40 /**
41  * Mapping from device states into {@link Layout}s. This allows us to map device
42  * states into specific layouts for the connected displays; particularly useful for
43  * foldable and multi-display devices where the default display and which displays are ON can
44  * change depending on the state of the device.
45  */
46 class DeviceStateToLayoutMap {
47     private static final String TAG = "DeviceStateToLayoutMap";
48 
49     public static final int STATE_DEFAULT = DeviceStateManager.INVALID_DEVICE_STATE;
50 
51     private static final String CONFIG_FILE_PATH =
52             "etc/displayconfig/display_layout_configuration.xml";
53 
54     private final SparseArray<Layout> mLayoutMap = new SparseArray<>();
55 
DeviceStateToLayoutMap()56     DeviceStateToLayoutMap() {
57         loadLayoutsFromConfig();
58         createLayout(STATE_DEFAULT);
59     }
60 
dumpLocked(IndentingPrintWriter ipw)61     public void dumpLocked(IndentingPrintWriter ipw) {
62         ipw.println("DeviceStateToLayoutMap:");
63         ipw.increaseIndent();
64 
65         ipw.println("Registered Layouts:");
66         for (int i = 0; i < mLayoutMap.size(); i++) {
67             ipw.println("state(" + mLayoutMap.keyAt(i) + "): " + mLayoutMap.valueAt(i));
68         }
69     }
70 
get(int state)71     Layout get(int state) {
72         Layout layout = mLayoutMap.get(state);
73         if (layout == null) {
74             layout = mLayoutMap.get(STATE_DEFAULT);
75         }
76         return layout;
77     }
78 
size()79     int size() {
80         return mLayoutMap.size();
81     }
82 
createLayout(int state)83     private Layout createLayout(int state) {
84         if (mLayoutMap.contains(state)) {
85             Slog.e(TAG, "Attempted to create a second layout for state " + state);
86             return null;
87         }
88 
89         final Layout layout = new Layout();
90         mLayoutMap.append(state, layout);
91         return layout;
92     }
93 
94     /**
95      * Reads display-layout-configuration files to get the layouts to use for this device.
96      */
loadLayoutsFromConfig()97     private void loadLayoutsFromConfig() {
98         final File configFile = Environment.buildPath(
99                 Environment.getVendorDirectory(), CONFIG_FILE_PATH);
100 
101         if (!configFile.exists()) {
102             return;
103         }
104 
105         Slog.i(TAG, "Loading display layouts from " + configFile);
106         try (InputStream in = new BufferedInputStream(new FileInputStream(configFile))) {
107             final Layouts layouts = XmlParser.read(in);
108             if (layouts == null) {
109                 Slog.i(TAG, "Display layout config not found: " + configFile);
110                 return;
111             }
112             for (com.android.server.display.config.layout.Layout l : layouts.getLayout()) {
113                 final int state = l.getState().intValue();
114                 final Layout layout = createLayout(state);
115                 for (com.android.server.display.config.layout.Display d: l.getDisplay()) {
116                     layout.createDisplayLocked(
117                             DisplayAddress.fromPhysicalDisplayId(d.getAddress().longValue()),
118                             d.isDefaultDisplay(),
119                             d.isEnabled());
120                 }
121             }
122         } catch (IOException | DatatypeConfigurationException | XmlPullParserException e) {
123             Slog.e(TAG, "Encountered an error while reading/parsing display layout config file: "
124                     + configFile, e);
125         }
126     }
127 }
128