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