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.wm;
18 
19 import android.hardware.display.DisplayManagerInternal;
20 import android.util.ArraySet;
21 import android.util.Slog;
22 import android.util.SparseArray;
23 import android.view.DisplayInfo;
24 
25 import java.util.ArrayList;
26 import java.util.List;
27 import java.util.Set;
28 
29 /**
30  * Maintains a map of possible {@link DisplayInfo} for displays and states that may be encountered
31  * on a device. This is not guaranteed to include all possible device states for all displays.
32  *
33  * By 'possible', this class only handles device states for displays and display groups it is
34  * currently aware of. It can not handle all eventual states the system may enter, for example, if
35  * an external display is added, or a new display is added to the group.
36  */
37 public class PossibleDisplayInfoMapper {
38     private static final String TAG = "PossibleDisplayInfoMapper";
39     private static final boolean DEBUG = false;
40 
41     private final DisplayManagerInternal mDisplayManagerInternal;
42 
43     /**
44      * Map of all logical displays, indexed by logical display id.
45      * Each logical display has multiple entries, one for each device state.
46      *
47      * Emptied and re-calculated when a display is added, removed, or changed.
48      */
49     private final SparseArray<Set<DisplayInfo>> mDisplayInfos = new SparseArray<>();
50 
PossibleDisplayInfoMapper(DisplayManagerInternal displayManagerInternal)51     PossibleDisplayInfoMapper(DisplayManagerInternal displayManagerInternal) {
52         mDisplayManagerInternal = displayManagerInternal;
53     }
54 
55 
56     /**
57      * Returns, for the given displayId, a list of unique display infos. List contains each
58      * supported device state.
59      * <p>List contents are guaranteed to be unique, but returned as a list rather than a set to
60      * minimize copies needed to make an iteraable data structure.
61      */
getPossibleDisplayInfos(int displayId)62     public List<DisplayInfo> getPossibleDisplayInfos(int displayId) {
63         // Update display infos before returning, since any cached values would have been removed
64         // in response to any display event. This model avoids re-computing the cache for every
65         // display change event (which occurs extremely frequently in the normal usage of the
66         // device).
67         updatePossibleDisplayInfos(displayId);
68         if (!mDisplayInfos.contains(displayId)) {
69             return new ArrayList<>();
70         }
71         return List.copyOf(mDisplayInfos.get(displayId));
72     }
73 
74     /**
75      * Updates the possible {@link DisplayInfo}s for the given display, by saving the DisplayInfo
76      * across supported device states.
77      */
updatePossibleDisplayInfos(int displayId)78     public void updatePossibleDisplayInfos(int displayId) {
79         Set<DisplayInfo> displayInfos = mDisplayManagerInternal.getPossibleDisplayInfo(displayId);
80         if (DEBUG) {
81             Slog.v(TAG, "updatePossibleDisplayInfos, given DisplayInfo "
82                     + displayInfos.size() + " on display " + displayId);
83         }
84         updateDisplayInfos(displayInfos);
85     }
86 
87     /**
88      * For the given displayId, removes all possible {@link DisplayInfo}.
89      */
removePossibleDisplayInfos(int displayId)90     public void removePossibleDisplayInfos(int displayId) {
91         if (DEBUG && mDisplayInfos.get(displayId) != null) {
92             Slog.v(TAG, "onDisplayRemoved, remove all DisplayInfo (" + mDisplayInfos.get(
93                     displayId).size() + ") with id " + displayId);
94         }
95         mDisplayInfos.remove(displayId);
96     }
97 
updateDisplayInfos(Set<DisplayInfo> displayInfos)98     private void updateDisplayInfos(Set<DisplayInfo> displayInfos) {
99         // Empty out cache before re-computing.
100         mDisplayInfos.clear();
101         // Iterate over each logical display layout for the current state.
102         for (DisplayInfo di : displayInfos) {
103             // Combine all results under the logical display id.
104             Set<DisplayInfo> priorDisplayInfos = mDisplayInfos.get(di.displayId, new ArraySet<>());
105             priorDisplayInfos.add(di);
106             mDisplayInfos.put(di.displayId, priorDisplayInfos);
107         }
108     }
109 }
110