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.layout; 18 19 import static android.view.Display.DEFAULT_DISPLAY; 20 21 import android.annotation.NonNull; 22 import android.annotation.Nullable; 23 import android.util.Slog; 24 import android.view.DisplayAddress; 25 26 import java.util.ArrayList; 27 import java.util.List; 28 29 /** 30 * Holds a collection of {@link Display}s. A single instance of this class describes 31 * how to organize one or more DisplayDevices into LogicalDisplays for a particular device 32 * state. For example, there may be one instance of this class to describe display layout when 33 * a foldable device is folded, and a second instance for when the device is unfolded. 34 */ 35 public class Layout { 36 private static final String TAG = "Layout"; 37 private static int sNextNonDefaultDisplayId = DEFAULT_DISPLAY + 1; 38 39 private final List<Display> mDisplays = new ArrayList<>(2); 40 41 /** 42 * @return The default display ID, or a new unique one to use. 43 */ assignDisplayIdLocked(boolean isDefault)44 public static int assignDisplayIdLocked(boolean isDefault) { 45 return isDefault ? DEFAULT_DISPLAY : sNextNonDefaultDisplayId++; 46 } 47 48 @Override toString()49 public String toString() { 50 return mDisplays.toString(); 51 } 52 53 /** 54 * Creates a simple 1:1 LogicalDisplay mapping for the specified DisplayDevice. 55 * 56 * @param address Address of the device. 57 * @param isDefault Indicates if the device is meant to be the default display. 58 * @return The new layout. 59 */ createDisplayLocked( @onNull DisplayAddress address, boolean isDefault, boolean isEnabled)60 public Display createDisplayLocked( 61 @NonNull DisplayAddress address, boolean isDefault, boolean isEnabled) { 62 if (contains(address)) { 63 Slog.w(TAG, "Attempting to add second definition for display-device: " + address); 64 return null; 65 } 66 67 // See if we're dealing with the "default" display 68 if (isDefault && getById(DEFAULT_DISPLAY) != null) { 69 Slog.w(TAG, "Ignoring attempt to add a second default display: " + address); 70 return null; 71 } 72 73 // Assign a logical display ID and create the new display. 74 // Note that the logical display ID is saved into the layout, so when switching between 75 // different layouts, a logical display can be destroyed and later recreated with the 76 // same logical display ID. 77 final int logicalDisplayId = assignDisplayIdLocked(isDefault); 78 final Display display = new Display(address, logicalDisplayId, isEnabled); 79 80 mDisplays.add(display); 81 return display; 82 } 83 84 /** 85 * @param id The ID of the display to remove. 86 */ removeDisplayLocked(int id)87 public void removeDisplayLocked(int id) { 88 Display display = getById(id); 89 if (display != null) { 90 mDisplays.remove(display); 91 } 92 } 93 94 /** 95 * @param address The address to check. 96 * 97 * @return True if the specified address is used in this layout. 98 */ contains(@onNull DisplayAddress address)99 public boolean contains(@NonNull DisplayAddress address) { 100 final int size = mDisplays.size(); 101 for (int i = 0; i < size; i++) { 102 if (address.equals(mDisplays.get(i).getAddress())) { 103 return true; 104 } 105 } 106 return false; 107 } 108 109 /** 110 * @param id The display ID to check. 111 * 112 * @return The display corresponding to the specified display ID. 113 */ 114 @Nullable getById(int id)115 public Display getById(int id) { 116 for (int i = 0; i < mDisplays.size(); i++) { 117 Display display = mDisplays.get(i); 118 if (id == display.getLogicalDisplayId()) { 119 return display; 120 } 121 } 122 return null; 123 } 124 125 /** 126 * @param address The display address to check. 127 * 128 * @return The display corresponding to the specified address. 129 */ 130 @Nullable getByAddress(@onNull DisplayAddress address)131 public Display getByAddress(@NonNull DisplayAddress address) { 132 for (int i = 0; i < mDisplays.size(); i++) { 133 Display display = mDisplays.get(i); 134 if (address.equals(display.getAddress())) { 135 return display; 136 } 137 } 138 return null; 139 } 140 141 /** 142 * @param index The index of the display to return. 143 * 144 * @return the display at the specified index. 145 */ getAt(int index)146 public Display getAt(int index) { 147 return mDisplays.get(index); 148 } 149 150 /** 151 * @return The number of displays defined for this layout. 152 */ size()153 public int size() { 154 return mDisplays.size(); 155 } 156 157 /** 158 * Describes how a {@link LogicalDisplay} is built from {@link DisplayDevice}s. 159 */ 160 public static class Display { 161 // Address of the display device to map to this display. 162 private final DisplayAddress mAddress; 163 164 // Logical Display ID to apply to this display. 165 private final int mLogicalDisplayId; 166 167 // Indicates that this display is not usable and should remain off. 168 private final boolean mIsEnabled; 169 Display(@onNull DisplayAddress address, int logicalDisplayId, boolean isEnabled)170 Display(@NonNull DisplayAddress address, int logicalDisplayId, boolean isEnabled) { 171 mAddress = address; 172 mLogicalDisplayId = logicalDisplayId; 173 mIsEnabled = isEnabled; 174 } 175 176 @Override toString()177 public String toString() { 178 return "{addr: " + mAddress + ", dispId: " + mLogicalDisplayId 179 + "(" + (mIsEnabled ? "ON" : "OFF") + ")}"; 180 } 181 getAddress()182 public DisplayAddress getAddress() { 183 return mAddress; 184 } 185 getLogicalDisplayId()186 public int getLogicalDisplayId() { 187 return mLogicalDisplayId; 188 } 189 isEnabled()190 public boolean isEnabled() { 191 return mIsEnabled; 192 } 193 } 194 } 195