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