blob: 468bf21f8fd7697b1230742a814e955a550bbc6b [file] [log] [blame]
Jeff Brownfa25bf52012-07-23 19:26:30 -07001/*
2 * Copyright (C) 2012 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.server.display;
18
19import android.Manifest;
20import android.content.Context;
21import android.content.pm.PackageManager;
22import android.hardware.display.IDisplayManager;
23import android.os.Binder;
24import android.os.SystemProperties;
Craig Mautner4f67ba62012-08-02 11:23:00 -070025import android.util.Slog;
26import android.util.SparseArray;
Jeff Brownfa25bf52012-07-23 19:26:30 -070027import android.view.Display;
28import android.view.DisplayInfo;
29import android.view.Surface;
30
31import java.io.FileDescriptor;
32import java.io.PrintWriter;
33import java.util.ArrayList;
34
35/**
36 * Manages the properties, media routing and power state of attached displays.
37 * <p>
38 * The display manager service does not own or directly control the displays.
39 * Instead, other components in the system register their display adapters with the
40 * display manager service which acts as a central controller.
41 * </p>
42 */
43public final class DisplayManagerService extends IDisplayManager.Stub {
44 private static final String TAG = "DisplayManagerService";
45
46 private static final String SYSTEM_HEADLESS = "ro.config.headless";
47
48 private final Object mLock = new Object();
49
50 private Context mContext;
51 private final boolean mHeadless;
Craig Mautner4f67ba62012-08-02 11:23:00 -070052
53 private int mDisplayIdSeq = Display.DEFAULT_DISPLAY;
54
55 /** All registered DisplayAdapters. */
Jeff Brownfa25bf52012-07-23 19:26:30 -070056 private final ArrayList<DisplayAdapter> mDisplayAdapters = new ArrayList<DisplayAdapter>();
57
Craig Mautner4f67ba62012-08-02 11:23:00 -070058 /** All the DisplayAdapters showing the given displayId. */
59 private final SparseArray<ArrayList<DisplayAdapter>> mLogicalToPhysicals =
60 new SparseArray<ArrayList<DisplayAdapter>>();
61
62 /** All the DisplayInfos in the system indexed by deviceId */
63 private final SparseArray<DisplayInfo> mDisplayInfos = new SparseArray<DisplayInfo>();
Jeff Brownfa25bf52012-07-23 19:26:30 -070064
Craig Mautner9de49362012-08-02 14:30:30 -070065 private final ArrayList<DisplayCallback> mCallbacks =
66 new ArrayList<DisplayManagerService.DisplayCallback>();
67
Jeff Brownfa25bf52012-07-23 19:26:30 -070068 public DisplayManagerService() {
69 mHeadless = SystemProperties.get(SYSTEM_HEADLESS).equals("1");
Craig Mautner4f67ba62012-08-02 11:23:00 -070070 registerDefaultDisplayAdapter();
71 }
72
73 private void registerDefaultDisplayAdapter() {
74 if (mHeadless) {
75 registerDisplayAdapter(new HeadlessDisplayAdapter());
76 } else {
77 registerDisplayAdapter(new SurfaceFlingerDisplayAdapter());
78 }
Jeff Brownfa25bf52012-07-23 19:26:30 -070079 }
80
81 public void setContext(Context context) {
82 mContext = context;
83 }
84
85 // FIXME: this isn't the right API for the long term
Jeff Brownfa25bf52012-07-23 19:26:30 -070086 public void getDefaultExternalDisplayDeviceInfo(DisplayDeviceInfo info) {
87 // hardcoded assuming 720p touch screen plugged into HDMI and USB
88 // need to redesign this
89 info.width = 1280;
90 info.height = 720;
91 }
92
93 public boolean isHeadless() {
94 return mHeadless;
95 }
96
Craig Mautner4f67ba62012-08-02 11:23:00 -070097 /**
98 * Save away new DisplayInfo data.
99 * @param displayId The local DisplayInfo to store the new data in.
100 * @param info The new data to be stored.
101 */
102 public void setDisplayInfo(int displayId, DisplayInfo info) {
103 synchronized (mLock) {
104 DisplayInfo localInfo = mDisplayInfos.get(displayId);
105 if (localInfo == null) {
106 localInfo = new DisplayInfo();
107 mDisplayInfos.put(displayId, localInfo);
108 }
109 localInfo.copyFrom(info);
110 }
111 }
112
113 /**
114 * Return requested DisplayInfo.
115 * @param displayId The data to retrieve.
116 * @param outInfo The structure to receive the data.
117 */
Jeff Brownfa25bf52012-07-23 19:26:30 -0700118 @Override // Binder call
119 public boolean getDisplayInfo(int displayId, DisplayInfo outInfo) {
120 synchronized (mLock) {
Craig Mautner4f67ba62012-08-02 11:23:00 -0700121 DisplayInfo localInfo = mDisplayInfos.get(displayId);
122 if (localInfo == null) {
123 return false;
Jeff Brownfa25bf52012-07-23 19:26:30 -0700124 }
Craig Mautner4f67ba62012-08-02 11:23:00 -0700125 outInfo.copyFrom(localInfo);
126 return true;
Jeff Brownfa25bf52012-07-23 19:26:30 -0700127 }
128 }
129
Craig Mautner4f67ba62012-08-02 11:23:00 -0700130 /**
131 * Inform the service of a new physical display. A new logical displayId is created and the new
132 * physical display is immediately bound to it. Use removeAdapterFromDisplay to disconnect it.
133 *
134 * @param adapter The wrapper for information associated with the physical display.
135 */
136 public void registerDisplayAdapter(DisplayAdapter adapter) {
Craig Mautner9de49362012-08-02 14:30:30 -0700137
138 int displayId;
139 DisplayCallback[] callbacks;
140
Craig Mautner4f67ba62012-08-02 11:23:00 -0700141 synchronized (mLock) {
Craig Mautner9de49362012-08-02 14:30:30 -0700142 displayId = mDisplayIdSeq;
143 do {
144 // Find the next unused displayId. (Pretend like it might ever wrap around).
145 mDisplayIdSeq++;
146 if (mDisplayIdSeq < 0) {
147 mDisplayIdSeq = Display.DEFAULT_DISPLAY + 1;
148 }
149 } while (mDisplayInfos.get(mDisplayIdSeq) != null);
150
Craig Mautner4f67ba62012-08-02 11:23:00 -0700151 adapter.setDisplayId(displayId);
152
153 createDisplayInfoLocked(displayId, adapter);
154
155 ArrayList<DisplayAdapter> list = new ArrayList<DisplayAdapter>();
156 list.add(adapter);
157 mLogicalToPhysicals.put(displayId, list);
158
159 mDisplayAdapters.add(adapter);
Craig Mautner9de49362012-08-02 14:30:30 -0700160 callbacks = mCallbacks.toArray(new DisplayCallback[mCallbacks.size()]);
161 }
162
163 for (int i = callbacks.length - 1; i >= 0; i--) {
164 callbacks[i].displayAdded(displayId);
Craig Mautner4f67ba62012-08-02 11:23:00 -0700165 }
166
167 // TODO: Notify SurfaceFlinger of new addition.
168 }
169
170 /**
171 * Connect a logical display to a physical display. Will remove the physical display from any
172 * logical display it is currently attached to.
173 *
174 * @param displayId The logical display. Will be created if it does not already exist.
175 * @param adapter The physical display.
176 */
177 public void addAdapterToDisplay(int displayId, DisplayAdapter adapter) {
178 if (adapter == null) {
179 // TODO: Or throw NPE?
180 Slog.e(TAG, "addDeviceToDisplay: Attempt to add null adapter");
181 return;
182 }
183
184 synchronized (mLock) {
185 if (!mDisplayAdapters.contains(adapter)) {
186 // TOOD: Handle unregistered adapter with exception or return value.
187 Slog.e(TAG, "addDeviceToDisplay: Attempt to add an unregistered adapter");
188 return;
189 }
190
191 DisplayInfo displayInfo = mDisplayInfos.get(displayId);
192 if (displayInfo == null) {
193 createDisplayInfoLocked(displayId, adapter);
194 }
195
196 Integer oldDisplayId = adapter.getDisplayId();
197 if (oldDisplayId != Display.NO_DISPLAY) {
198 if (oldDisplayId == displayId) {
199 // adapter already added to displayId.
200 return;
201 }
202
203 removeAdapterLocked(adapter);
204 }
205
206 ArrayList<DisplayAdapter> list = mLogicalToPhysicals.get(displayId);
207 if (list == null) {
208 list = new ArrayList<DisplayAdapter>();
209 mLogicalToPhysicals.put(displayId, list);
210 }
Craig Mautner4f67ba62012-08-02 11:23:00 -0700211 list.add(adapter);
212 adapter.setDisplayId(displayId);
213 }
214
215 // TODO: Notify SurfaceFlinger of new addition.
216 }
217
218 /**
219 * Disconnect the physical display from whichever logical display it is attached to.
220 * @param adapter The physical display to detach.
221 */
222 public void removeAdapterFromDisplay(DisplayAdapter adapter) {
223 if (adapter == null) {
224 // TODO: Or throw NPE?
225 return;
226 }
227
228 synchronized (mLock) {
229 if (!mDisplayAdapters.contains(adapter)) {
230 // TOOD: Handle unregistered adapter with exception or return value.
231 Slog.e(TAG, "removeDeviceFromDisplay: Attempt to remove an unregistered adapter");
232 return;
233 }
234
235 removeAdapterLocked(adapter);
236 }
237
238 // TODO: Notify SurfaceFlinger of removal.
239 }
240
Craig Mautner9de49362012-08-02 14:30:30 -0700241 public void registerDisplayCallback(final DisplayCallback callback) {
242 synchronized (mLock) {
243 if (!mCallbacks.contains(callback)) {
244 mCallbacks.add(callback);
245 }
246 }
247 }
248
249 public void unregisterDisplayCallback(final DisplayCallback callback) {
250 synchronized (mLock) {
251 mCallbacks.remove(callback);
252 }
253 }
254
Craig Mautner4f67ba62012-08-02 11:23:00 -0700255 /**
256 * Create a new logical DisplayInfo and fill it in with information from the physical display.
257 * @param displayId The logical identifier.
258 * @param adapter The physical display for initial values.
259 */
260 private void createDisplayInfoLocked(int displayId, DisplayAdapter adapter) {
261 DisplayInfo displayInfo = new DisplayInfo();
262 DisplayDeviceInfo deviceInfo = new DisplayDeviceInfo();
263 adapter.getDisplayDevice().getInfo(deviceInfo);
264 copyDisplayInfoFromDeviceInfo(displayInfo, deviceInfo);
265 mDisplayInfos.put(displayId, displayInfo);
266 }
267
268 /**
269 * Disconnect a physical display from its logical display. If there are no more physical
270 * displays attached to the logical display, delete the logical display.
271 * @param adapter The physical display to detach.
272 */
273 void removeAdapterLocked(DisplayAdapter adapter) {
274 int displayId = adapter.getDisplayId();
275 adapter.setDisplayId(Display.NO_DISPLAY);
276
277 ArrayList<DisplayAdapter> list = mLogicalToPhysicals.get(displayId);
278 if (list != null) {
279 list.remove(adapter);
280 if (list.isEmpty()) {
281 mLogicalToPhysicals.remove(displayId);
282 // TODO: Keep count of Windows attached to logical display and don't delete if
283 // there are any outstanding. Also, what keeps the WindowManager from continuing
284 // to use the logical display?
285 mDisplayInfos.remove(displayId);
286 }
287 }
288 }
289
290 private void copyDisplayInfoFromDeviceInfo(DisplayInfo displayInfo,
291 DisplayDeviceInfo deviceInfo) {
292 // Bootstrap the logical display using the physical display.
293 displayInfo.appWidth = deviceInfo.width;
294 displayInfo.appHeight = deviceInfo.height;
295 displayInfo.logicalWidth = deviceInfo.width;
296 displayInfo.logicalHeight = deviceInfo.height;
297 displayInfo.rotation = Surface.ROTATION_0;
298 displayInfo.refreshRate = deviceInfo.refreshRate;
299 displayInfo.logicalDensityDpi = deviceInfo.densityDpi;
300 displayInfo.physicalXDpi = deviceInfo.xDpi;
301 displayInfo.physicalYDpi = deviceInfo.yDpi;
302 displayInfo.smallestNominalAppWidth = deviceInfo.width;
303 displayInfo.smallestNominalAppHeight = deviceInfo.height;
304 displayInfo.largestNominalAppWidth = deviceInfo.width;
305 displayInfo.largestNominalAppHeight = deviceInfo.height;
306 }
307
Jeff Brownfa25bf52012-07-23 19:26:30 -0700308 @Override // Binder call
309 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
310 if (mContext == null
311 || mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
312 != PackageManager.PERMISSION_GRANTED) {
313 pw.println("Permission Denial: can't dump DisplayManager from from pid="
314 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
315 return;
316 }
317
318 pw.println("DISPLAY MANAGER (dumpsys display)\n");
319
320 pw.println("Headless: " + mHeadless);
321
322 DisplayDeviceInfo info = new DisplayDeviceInfo();
323 for (DisplayAdapter adapter : mDisplayAdapters) {
Craig Mautner9de49362012-08-02 14:30:30 -0700324 pw.println("Display for adapter " + adapter.getName()
325 + " assigned to Display " + adapter.getDisplayId());
Craig Mautner4f67ba62012-08-02 11:23:00 -0700326 DisplayDevice device = adapter.getDisplayDevice();
327 pw.print(" ");
328 device.getInfo(info);
329 pw.println(info);
Jeff Brownfa25bf52012-07-23 19:26:30 -0700330 }
331 }
Craig Mautner9de49362012-08-02 14:30:30 -0700332
333 public interface DisplayCallback {
334 public void displayAdded(int displayId);
335 public void displayRemoved(int displayId);
336 }
Jeff Brownfa25bf52012-07-23 19:26:30 -0700337}