blob: bc24ad0118e7079f887a058fcc2108814b44ce35 [file] [log] [blame]
Evan Rosky69cace42019-09-20 16:28:13 -07001/*
2 * Copyright (C) 2019 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
17package com.android.systemui.wm;
18
Evan Roskycfa31de2019-11-21 19:09:43 -080019import android.annotation.Nullable;
20import android.content.Context;
Evan Rosky82207082019-10-08 17:28:29 -070021import android.content.res.Configuration;
Evan Roskycfa31de2019-11-21 19:09:43 -080022import android.hardware.display.DisplayManager;
Evan Rosky69cace42019-09-20 16:28:13 -070023import android.os.Handler;
24import android.os.RemoteException;
Evan Rosky82207082019-10-08 17:28:29 -070025import android.util.Slog;
Evan Rosky69cace42019-09-20 16:28:13 -070026import android.util.SparseArray;
Evan Roskycfa31de2019-11-21 19:09:43 -080027import android.view.Display;
Evan Rosky69cace42019-09-20 16:28:13 -070028import android.view.IDisplayWindowListener;
Evan Roskycfa31de2019-11-21 19:09:43 -080029import android.view.IWindowManager;
Evan Rosky69cace42019-09-20 16:28:13 -070030
Dave Mankoff00e8a2f2019-12-18 16:59:49 -050031import com.android.systemui.dagger.qualifiers.Main;
Winson Chung95c9fca2020-01-22 09:48:40 -080032import com.android.systemui.wm.DisplayChangeController.OnDisplayChangingListener;
Evan Rosky69cace42019-09-20 16:28:13 -070033
34import java.util.ArrayList;
35
36import javax.inject.Inject;
37import javax.inject.Singleton;
38
39/**
40 * This module deals with display rotations coming from WM. When WM starts a rotation: after it has
41 * frozen the screen, it will call into this class. This will then call all registered local
42 * controllers and give them a chance to queue up task changes to be applied synchronously with that
43 * rotation.
44 */
45@Singleton
Winson Chung95c9fca2020-01-22 09:48:40 -080046public class DisplayController {
47 private static final String TAG = "DisplayController";
Evan Rosky82207082019-10-08 17:28:29 -070048
Evan Rosky69cace42019-09-20 16:28:13 -070049 private final Handler mHandler;
Evan Roskycfa31de2019-11-21 19:09:43 -080050 private final Context mContext;
51 private final IWindowManager mWmService;
Winson Chung95c9fca2020-01-22 09:48:40 -080052 private final DisplayChangeController mChangeController;
Evan Rosky69cace42019-09-20 16:28:13 -070053
54 private final SparseArray<DisplayRecord> mDisplays = new SparseArray<>();
Winson Chung95c9fca2020-01-22 09:48:40 -080055 private final ArrayList<OnDisplaysChangedListener> mDisplayChangedListeners = new ArrayList<>();
Evan Rosky69cace42019-09-20 16:28:13 -070056
Evan Roskycfa31de2019-11-21 19:09:43 -080057 /**
58 * Get's a display by id from DisplayManager.
59 */
60 public Display getDisplay(int displayId) {
61 final DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
62 return displayManager.getDisplay(displayId);
63 }
64
Evan Rosky69cace42019-09-20 16:28:13 -070065 private final IDisplayWindowListener mDisplayContainerListener =
66 new IDisplayWindowListener.Stub() {
67 @Override
68 public void onDisplayAdded(int displayId) {
69 mHandler.post(() -> {
70 synchronized (mDisplays) {
71 if (mDisplays.get(displayId) != null) {
72 return;
73 }
Evan Roskye577f782019-12-19 17:19:32 -080074 Display display = getDisplay(displayId);
75 if (display == null) {
76 // It's likely that the display is private to some app and thus not
77 // accessible by system-ui.
78 return;
79 }
Evan Rosky69cace42019-09-20 16:28:13 -070080 DisplayRecord record = new DisplayRecord();
81 record.mDisplayId = displayId;
Evan Roskye577f782019-12-19 17:19:32 -080082 record.mContext = (displayId == Display.DEFAULT_DISPLAY) ? mContext
83 : mContext.createDisplayContext(display);
84 record.mDisplayLayout = new DisplayLayout(record.mContext, display);
Evan Rosky69cace42019-09-20 16:28:13 -070085 mDisplays.put(displayId, record);
Evan Rosky82207082019-10-08 17:28:29 -070086 for (int i = 0; i < mDisplayChangedListeners.size(); ++i) {
87 mDisplayChangedListeners.get(i).onDisplayAdded(displayId);
88 }
89 }
90 });
91 }
92
93 @Override
94 public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
95 mHandler.post(() -> {
96 synchronized (mDisplays) {
97 DisplayRecord dr = mDisplays.get(displayId);
98 if (dr == null) {
99 Slog.w(TAG, "Skipping Display Configuration change on non-added"
100 + " display.");
101 return;
102 }
Evan Roskye577f782019-12-19 17:19:32 -0800103 Display display = getDisplay(displayId);
104 Context perDisplayContext = mContext;
105 if (displayId != Display.DEFAULT_DISPLAY) {
106 perDisplayContext = mContext.createDisplayContext(display);
107 }
108 dr.mContext = perDisplayContext.createConfigurationContext(newConfig);
109 dr.mDisplayLayout = new DisplayLayout(dr.mContext, display);
Evan Rosky82207082019-10-08 17:28:29 -0700110 for (int i = 0; i < mDisplayChangedListeners.size(); ++i) {
111 mDisplayChangedListeners.get(i).onDisplayConfigurationChanged(
112 displayId, newConfig);
Evan Rosky69cace42019-09-20 16:28:13 -0700113 }
114 }
115 });
116 }
117
118 @Override
119 public void onDisplayRemoved(int displayId) {
120 mHandler.post(() -> {
121 synchronized (mDisplays) {
Evan Roskye577f782019-12-19 17:19:32 -0800122 if (mDisplays.get(displayId) == null) {
123 return;
124 }
Evan Rosky69cace42019-09-20 16:28:13 -0700125 for (int i = mDisplayChangedListeners.size() - 1; i >= 0; --i) {
126 mDisplayChangedListeners.get(i).onDisplayRemoved(displayId);
127 }
128 mDisplays.remove(displayId);
129 }
130 });
131 }
132 };
133
134 @Inject
Winson Chung95c9fca2020-01-22 09:48:40 -0800135 public DisplayController(Context context, @Main Handler mainHandler,
Evan Roskycfa31de2019-11-21 19:09:43 -0800136 IWindowManager wmService) {
Evan Rosky69cace42019-09-20 16:28:13 -0700137 mHandler = mainHandler;
Evan Roskycfa31de2019-11-21 19:09:43 -0800138 mContext = context;
139 mWmService = wmService;
Winson Chung95c9fca2020-01-22 09:48:40 -0800140 mChangeController = new DisplayChangeController(mHandler, mWmService);
Evan Rosky69cace42019-09-20 16:28:13 -0700141 try {
Evan Roskycfa31de2019-11-21 19:09:43 -0800142 mWmService.registerDisplayWindowListener(mDisplayContainerListener);
Evan Rosky69cace42019-09-20 16:28:13 -0700143 } catch (RemoteException e) {
144 throw new RuntimeException("Unable to register hierarchy listener");
145 }
146 }
147
148 /**
Evan Roskycfa31de2019-11-21 19:09:43 -0800149 * Gets the DisplayLayout associated with a display.
150 */
151 public @Nullable DisplayLayout getDisplayLayout(int displayId) {
152 final DisplayRecord r = mDisplays.get(displayId);
153 return r != null ? r.mDisplayLayout : null;
154 }
155
156 /**
157 * Gets a display-specific context for a display.
158 */
159 public @Nullable Context getDisplayContext(int displayId) {
160 final DisplayRecord r = mDisplays.get(displayId);
161 return r != null ? r.mContext : null;
162 }
163
164 /**
Evan Rosky82207082019-10-08 17:28:29 -0700165 * Add a display window-container listener. It will get notified whenever a display's
166 * configuration changes or when displays are added/removed from the WM hierarchy.
Evan Rosky69cace42019-09-20 16:28:13 -0700167 */
Winson Chung95c9fca2020-01-22 09:48:40 -0800168 public void addDisplayWindowListener(OnDisplaysChangedListener listener) {
Evan Rosky69cace42019-09-20 16:28:13 -0700169 synchronized (mDisplays) {
170 if (mDisplayChangedListeners.contains(listener)) {
171 return;
172 }
173 mDisplayChangedListeners.add(listener);
174 for (int i = 0; i < mDisplays.size(); ++i) {
175 listener.onDisplayAdded(mDisplays.keyAt(i));
176 }
177 }
178 }
179
180 /**
181 * Remove a display window-container listener.
182 */
Winson Chung95c9fca2020-01-22 09:48:40 -0800183 public void removeDisplayWindowListener(OnDisplaysChangedListener listener) {
Evan Rosky69cace42019-09-20 16:28:13 -0700184 synchronized (mDisplays) {
185 mDisplayChangedListeners.remove(listener);
186 }
187 }
188
189 /**
190 * Adds a display rotation controller.
191 */
Winson Chung95c9fca2020-01-22 09:48:40 -0800192 public void addDisplayChangingController(OnDisplayChangingListener controller) {
193 mChangeController.addRotationListener(controller);
Evan Rosky69cace42019-09-20 16:28:13 -0700194 }
195
196 /**
197 * Removes a display rotation controller.
198 */
Winson Chung95c9fca2020-01-22 09:48:40 -0800199 public void removeDisplayChangingController(OnDisplayChangingListener controller) {
200 mChangeController.removeRotationListener(controller);
Evan Rosky69cace42019-09-20 16:28:13 -0700201 }
202
203 private static class DisplayRecord {
204 int mDisplayId;
Evan Roskycfa31de2019-11-21 19:09:43 -0800205 Context mContext;
206 DisplayLayout mDisplayLayout;
Evan Rosky69cace42019-09-20 16:28:13 -0700207 }
208
209 /**
Evan Rosky82207082019-10-08 17:28:29 -0700210 * Gets notified when a display is added/removed to the WM hierarchy and when a display's
211 * window-configuration changes.
Evan Rosky69cace42019-09-20 16:28:13 -0700212 *
213 * @see IDisplayWindowListener
214 */
Winson Chung95c9fca2020-01-22 09:48:40 -0800215 public interface OnDisplaysChangedListener {
Evan Rosky69cace42019-09-20 16:28:13 -0700216 /**
217 * Called when a display has been added to the WM hierarchy.
218 */
Winson Chung95c9fca2020-01-22 09:48:40 -0800219 default void onDisplayAdded(int displayId) {}
Evan Rosky69cace42019-09-20 16:28:13 -0700220
221 /**
Evan Rosky82207082019-10-08 17:28:29 -0700222 * Called when a display's window-container configuration changes.
223 */
Winson Chung95c9fca2020-01-22 09:48:40 -0800224 default void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {}
Evan Rosky82207082019-10-08 17:28:29 -0700225
226 /**
Evan Rosky69cace42019-09-20 16:28:13 -0700227 * Called when a display is removed.
228 */
Winson Chung95c9fca2020-01-22 09:48:40 -0800229 default void onDisplayRemoved(int displayId) {}
Evan Rosky69cace42019-09-20 16:28:13 -0700230 }
231}