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 isDefault = false; 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 layout = new Display(address, logicalDisplayId, isEnabled); 79 80 mDisplays.add(layout); 81 return layout; 82 } 83 84 /** 85 * @param address The address to check. 86 * 87 * @return True if the specified address is used in this layout. 88 */ contains(@onNull DisplayAddress address)89 public boolean contains(@NonNull DisplayAddress address) { 90 final int size = mDisplays.size(); 91 for (int i = 0; i < size; i++) { 92 if (address.equals(mDisplays.get(i).getAddress())) { 93 return true; 94 } 95 } 96 return false; 97 } 98 99 /** 100 * @param id The display ID to check. 101 * 102 * @return The display corresponding to the specified display ID. 103 */ 104 @Nullable getById(int id)105 public Display getById(int id) { 106 for (int i = 0; i < mDisplays.size(); i++) { 107 Display display = mDisplays.get(i); 108 if (id == display.getLogicalDisplayId()) { 109 return display; 110 } 111 } 112 return null; 113 } 114 115 /** 116 * @param address The display address to check. 117 * 118 * @return The display corresponding to the specified address. 119 */ 120 @Nullable getByAddress(@onNull DisplayAddress address)121 public Display getByAddress(@NonNull DisplayAddress address) { 122 for (int i = 0; i < mDisplays.size(); i++) { 123 Display display = mDisplays.get(i); 124 if (address.equals(display.getAddress())) { 125 return display; 126 } 127 } 128 return null; 129 } 130 131 /** 132 * @param index The index of the display to return. 133 * 134 * @return the display at the specified index. 135 */ getAt(int index)136 public Display getAt(int index) { 137 return mDisplays.get(index); 138 } 139 140 /** 141 * @return The number of displays defined for this layout. 142 */ size()143 public int size() { 144 return mDisplays.size(); 145 } 146 147 /** 148 * Describes how a {@link LogicalDisplay} is built from {@link DisplayDevice}s. 149 */ 150 public static class Display { 151 // Address of the display device to map to this display. 152 private final DisplayAddress mAddress; 153 154 // Logical Display ID to apply to this display. 155 private final int mLogicalDisplayId; 156 157 // Indicates that this display is not usable and should remain off. 158 private final boolean mIsEnabled; 159 Display(@onNull DisplayAddress address, int logicalDisplayId, boolean isEnabled)160 Display(@NonNull DisplayAddress address, int logicalDisplayId, boolean isEnabled) { 161 mAddress = address; 162 mLogicalDisplayId = logicalDisplayId; 163 mIsEnabled = isEnabled; 164 } 165 166 @Override toString()167 public String toString() { 168 return "{addr: " + mAddress + ", dispId: " + mLogicalDisplayId 169 + "(" + (mIsEnabled ? "ON" : "OFF") + ")}"; 170 } 171 getAddress()172 public DisplayAddress getAddress() { 173 return mAddress; 174 } 175 getLogicalDisplayId()176 public int getLogicalDisplayId() { 177 return mLogicalDisplayId; 178 } 179 isEnabled()180 public boolean isEnabled() { 181 return mIsEnabled; 182 } 183 } 184 } 185