• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 package com.android.server.display;
18 
19 import android.content.Context;
20 import android.os.Handler;
21 import android.os.IBinder;
22 import android.os.Looper;
23 import android.os.SystemProperties;
24 import android.util.SparseArray;
25 import android.view.Display;
26 import android.view.DisplayEventReceiver;
27 import android.view.Surface;
28 import android.view.SurfaceControl;
29 import android.view.SurfaceControl.PhysicalDisplayInfo;
30 
31 import java.io.PrintWriter;
32 
33 /**
34  * A display adapter for the local displays managed by Surface Flinger.
35  * <p>
36  * Display adapters are guarded by the {@link DisplayManagerService.SyncRoot} lock.
37  * </p>
38  */
39 final class LocalDisplayAdapter extends DisplayAdapter {
40     private static final String TAG = "LocalDisplayAdapter";
41 
42     private static final int[] BUILT_IN_DISPLAY_IDS_TO_SCAN = new int[] {
43             SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN,
44             SurfaceControl.BUILT_IN_DISPLAY_ID_HDMI,
45     };
46 
47     private final SparseArray<LocalDisplayDevice> mDevices =
48             new SparseArray<LocalDisplayDevice>();
49     private HotplugDisplayEventReceiver mHotplugReceiver;
50 
51     private final SurfaceControl.PhysicalDisplayInfo mTempPhys = new SurfaceControl.PhysicalDisplayInfo();
52 
53     // Called with SyncRoot lock held.
LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot, Context context, Handler handler, Listener listener)54     public LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
55             Context context, Handler handler, Listener listener) {
56         super(syncRoot, context, handler, listener, TAG);
57     }
58 
59     @Override
registerLocked()60     public void registerLocked() {
61         super.registerLocked();
62 
63         mHotplugReceiver = new HotplugDisplayEventReceiver(getHandler().getLooper());
64 
65         for (int builtInDisplayId : BUILT_IN_DISPLAY_IDS_TO_SCAN) {
66             tryConnectDisplayLocked(builtInDisplayId);
67         }
68     }
69 
tryConnectDisplayLocked(int builtInDisplayId)70     private void tryConnectDisplayLocked(int builtInDisplayId) {
71         IBinder displayToken = SurfaceControl.getBuiltInDisplay(builtInDisplayId);
72         if (displayToken != null && SurfaceControl.getDisplayInfo(displayToken, mTempPhys)) {
73             LocalDisplayDevice device = mDevices.get(builtInDisplayId);
74             if (device == null) {
75                 // Display was added.
76                 device = new LocalDisplayDevice(displayToken, builtInDisplayId, mTempPhys);
77                 mDevices.put(builtInDisplayId, device);
78                 sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_ADDED);
79             } else if (device.updatePhysicalDisplayInfoLocked(mTempPhys)) {
80                 // Display properties changed.
81                 sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_CHANGED);
82             }
83         } else {
84             // The display is no longer available. Ignore the attempt to add it.
85             // If it was connected but has already been disconnected, we'll get a
86             // disconnect event that will remove it from mDevices.
87         }
88     }
89 
tryDisconnectDisplayLocked(int builtInDisplayId)90     private void tryDisconnectDisplayLocked(int builtInDisplayId) {
91         LocalDisplayDevice device = mDevices.get(builtInDisplayId);
92         if (device != null) {
93             // Display was removed.
94             mDevices.remove(builtInDisplayId);
95             sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_REMOVED);
96         }
97     }
98 
99     private final class LocalDisplayDevice extends DisplayDevice {
100         private final int mBuiltInDisplayId;
101         private final SurfaceControl.PhysicalDisplayInfo mPhys;
102 
103         private DisplayDeviceInfo mInfo;
104         private boolean mHavePendingChanges;
105         private boolean mBlanked;
106 
LocalDisplayDevice(IBinder displayToken, int builtInDisplayId, SurfaceControl.PhysicalDisplayInfo phys)107         public LocalDisplayDevice(IBinder displayToken, int builtInDisplayId,
108                 SurfaceControl.PhysicalDisplayInfo phys) {
109             super(LocalDisplayAdapter.this, displayToken);
110             mBuiltInDisplayId = builtInDisplayId;
111             mPhys = new SurfaceControl.PhysicalDisplayInfo(phys);
112         }
113 
updatePhysicalDisplayInfoLocked(SurfaceControl.PhysicalDisplayInfo phys)114         public boolean updatePhysicalDisplayInfoLocked(SurfaceControl.PhysicalDisplayInfo phys) {
115             if (!mPhys.equals(phys)) {
116                 mPhys.copyFrom(phys);
117                 mHavePendingChanges = true;
118                 return true;
119             }
120             return false;
121         }
122 
123         @Override
applyPendingDisplayDeviceInfoChangesLocked()124         public void applyPendingDisplayDeviceInfoChangesLocked() {
125             if (mHavePendingChanges) {
126                 mInfo = null;
127                 mHavePendingChanges = false;
128             }
129         }
130 
131         @Override
getDisplayDeviceInfoLocked()132         public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
133             if (mInfo == null) {
134                 mInfo = new DisplayDeviceInfo();
135                 mInfo.width = mPhys.width;
136                 mInfo.height = mPhys.height;
137                 mInfo.refreshRate = mPhys.refreshRate;
138 
139                 // Assume that all built-in displays that have secure output (eg. HDCP) also
140                 // support compositing from gralloc protected buffers.
141                 if (mPhys.secure) {
142                     mInfo.flags = DisplayDeviceInfo.FLAG_SECURE
143                             | DisplayDeviceInfo.FLAG_SUPPORTS_PROTECTED_BUFFERS;
144                 }
145 
146                 if (mBuiltInDisplayId == SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN) {
147                     mInfo.name = getContext().getResources().getString(
148                             com.android.internal.R.string.display_manager_built_in_display_name);
149                     mInfo.flags |= DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY
150                             | DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT;
151                     mInfo.type = Display.TYPE_BUILT_IN;
152                     mInfo.densityDpi = (int)(mPhys.density * 160 + 0.5f);
153                     mInfo.xDpi = mPhys.xDpi;
154                     mInfo.yDpi = mPhys.yDpi;
155                     mInfo.touch = DisplayDeviceInfo.TOUCH_INTERNAL;
156                 } else {
157                     mInfo.type = Display.TYPE_HDMI;
158                     mInfo.flags |= DisplayDeviceInfo.FLAG_PRESENTATION;
159                     mInfo.name = getContext().getResources().getString(
160                             com.android.internal.R.string.display_manager_hdmi_display_name);
161                     mInfo.touch = DisplayDeviceInfo.TOUCH_EXTERNAL;
162                     mInfo.setAssumedDensityForExternalDisplay(mPhys.width, mPhys.height);
163 
164                     // For demonstration purposes, allow rotation of the external display.
165                     // In the future we might allow the user to configure this directly.
166                     if ("portrait".equals(SystemProperties.get("persist.demo.hdmirotation"))) {
167                         mInfo.rotation = Surface.ROTATION_270;
168                     }
169                 }
170             }
171             return mInfo;
172         }
173 
174         @Override
blankLocked()175         public void blankLocked() {
176             mBlanked = true;
177             SurfaceControl.blankDisplay(getDisplayTokenLocked());
178         }
179 
180         @Override
unblankLocked()181         public void unblankLocked() {
182             mBlanked = false;
183             SurfaceControl.unblankDisplay(getDisplayTokenLocked());
184         }
185 
186         @Override
dumpLocked(PrintWriter pw)187         public void dumpLocked(PrintWriter pw) {
188             super.dumpLocked(pw);
189             pw.println("mBuiltInDisplayId=" + mBuiltInDisplayId);
190             pw.println("mPhys=" + mPhys);
191             pw.println("mBlanked=" + mBlanked);
192         }
193     }
194 
195     private final class HotplugDisplayEventReceiver extends DisplayEventReceiver {
HotplugDisplayEventReceiver(Looper looper)196         public HotplugDisplayEventReceiver(Looper looper) {
197             super(looper);
198         }
199 
200         @Override
onHotplug(long timestampNanos, int builtInDisplayId, boolean connected)201         public void onHotplug(long timestampNanos, int builtInDisplayId, boolean connected) {
202             synchronized (getSyncRoot()) {
203                 if (connected) {
204                     tryConnectDisplayLocked(builtInDisplayId);
205                 } else {
206                     tryDisconnectDisplayLocked(builtInDisplayId);
207                 }
208             }
209         }
210     }
211 }