OSDN Git Service

4fd006d7e70acc2767fe33ab73cc7f23c5b79c7b
[android-x86/frameworks-base.git] / services / core / java / com / android / server / display / LocalDisplayAdapter.java
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.Pair;
25 import android.util.Slog;
26 import android.util.SparseArray;
27 import android.view.Display;
28 import android.view.DisplayEventReceiver;
29 import android.view.Surface;
30 import android.view.SurfaceControl;
31
32 import java.io.PrintWriter;
33 import java.util.Arrays;
34
35 /**
36  * A display adapter for the local displays managed by Surface Flinger.
37  * <p>
38  * Display adapters are guarded by the {@link DisplayManagerService.SyncRoot} lock.
39  * </p>
40  */
41 final class LocalDisplayAdapter extends DisplayAdapter {
42     private static final String TAG = "LocalDisplayAdapter";
43
44     private static final int[] BUILT_IN_DISPLAY_IDS_TO_SCAN = new int[] {
45             SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN,
46             SurfaceControl.BUILT_IN_DISPLAY_ID_HDMI,
47     };
48
49     private final SparseArray<LocalDisplayDevice> mDevices =
50             new SparseArray<LocalDisplayDevice>();
51     private HotplugDisplayEventReceiver mHotplugReceiver;
52
53     // Called with SyncRoot lock held.
54     public LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
55             Context context, Handler handler, Listener listener) {
56         super(syncRoot, context, handler, listener, TAG);
57     }
58
59     @Override
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
70     private void tryConnectDisplayLocked(int builtInDisplayId) {
71         IBinder displayToken = SurfaceControl.getBuiltInDisplay(builtInDisplayId);
72         if (displayToken != null) {
73             SurfaceControl.PhysicalDisplayInfo[] configs =
74                     SurfaceControl.getDisplayConfigs(displayToken);
75             if (configs == null) {
76                 // There are no valid configs for this device, so we can't use it
77                 Slog.w(TAG, "No valid configs found for display device " +
78                         builtInDisplayId);
79                 return;
80             }
81             int activeConfig = SurfaceControl.getActiveConfig(displayToken);
82             if (activeConfig < 0) {
83                 // There is no active config, and for now we don't have the
84                 // policy to set one.
85                 Slog.w(TAG, "No active config found for display device " +
86                         builtInDisplayId);
87                 return;
88             }
89             LocalDisplayDevice device = mDevices.get(builtInDisplayId);
90             if (device == null) {
91                 // Display was added.
92                 device = new LocalDisplayDevice(displayToken, builtInDisplayId,
93                         configs, activeConfig);
94                 mDevices.put(builtInDisplayId, device);
95                 sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_ADDED);
96             } else if (device.updatePhysicalDisplayInfoLocked(configs, activeConfig)) {
97                 // Display properties changed.
98                 sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_CHANGED);
99             }
100         } else {
101             // The display is no longer available. Ignore the attempt to add it.
102             // If it was connected but has already been disconnected, we'll get a
103             // disconnect event that will remove it from mDevices.
104         }
105     }
106
107     private void tryDisconnectDisplayLocked(int builtInDisplayId) {
108         LocalDisplayDevice device = mDevices.get(builtInDisplayId);
109         if (device != null) {
110             // Display was removed.
111             mDevices.remove(builtInDisplayId);
112             sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_REMOVED);
113         }
114     }
115
116     static int getPowerModeForState(int state) {
117         switch (state) {
118             case Display.STATE_OFF:
119                 return SurfaceControl.POWER_MODE_OFF;
120             case Display.STATE_DOZE:
121                 return SurfaceControl.POWER_MODE_DOZE;
122             case Display.STATE_DOZE_SUSPEND:
123                 return SurfaceControl.POWER_MODE_DOZE_SUSPEND;
124             default:
125                 return SurfaceControl.POWER_MODE_NORMAL;
126         }
127     }
128
129     private final class LocalDisplayDevice extends DisplayDevice {
130         private final int mBuiltInDisplayId;
131         private final SurfaceControl.PhysicalDisplayInfo mPhys;
132         private final int mDefaultPhysicalDisplayInfo;
133
134         private DisplayDeviceInfo mInfo;
135         private boolean mHavePendingChanges;
136         private int mState = Display.STATE_UNKNOWN;
137         private float[] mSupportedRefreshRates;
138         private int[] mRefreshRateConfigIndices;
139         private float mLastRequestedRefreshRate;
140
141         public LocalDisplayDevice(IBinder displayToken, int builtInDisplayId,
142                 SurfaceControl.PhysicalDisplayInfo[] physicalDisplayInfos, int activeDisplayInfo) {
143             super(LocalDisplayAdapter.this, displayToken);
144             mBuiltInDisplayId = builtInDisplayId;
145             mPhys = new SurfaceControl.PhysicalDisplayInfo(
146                     physicalDisplayInfos[activeDisplayInfo]);
147             mDefaultPhysicalDisplayInfo = activeDisplayInfo;
148             updateSupportedRefreshRatesLocked(physicalDisplayInfos, mPhys);
149         }
150
151         public boolean updatePhysicalDisplayInfoLocked(
152                 SurfaceControl.PhysicalDisplayInfo[] physicalDisplayInfos, int activeDisplayInfo) {
153             SurfaceControl.PhysicalDisplayInfo newPhys = physicalDisplayInfos[activeDisplayInfo];
154             if (!mPhys.equals(newPhys)) {
155                 mPhys.copyFrom(newPhys);
156                 updateSupportedRefreshRatesLocked(physicalDisplayInfos, mPhys);
157                 mHavePendingChanges = true;
158                 return true;
159             }
160             return false;
161         }
162
163         @Override
164         public void applyPendingDisplayDeviceInfoChangesLocked() {
165             if (mHavePendingChanges) {
166                 mInfo = null;
167                 mHavePendingChanges = false;
168             }
169         }
170
171         @Override
172         public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
173             if (mInfo == null) {
174                 mInfo = new DisplayDeviceInfo();
175                 mInfo.width = mPhys.width;
176                 mInfo.height = mPhys.height;
177                 mInfo.refreshRate = mPhys.refreshRate;
178                 mInfo.supportedRefreshRates = mSupportedRefreshRates;
179                 mInfo.appVsyncOffsetNanos = mPhys.appVsyncOffsetNanos;
180                 mInfo.presentationDeadlineNanos = mPhys.presentationDeadlineNanos;
181                 mInfo.state = mState;
182
183                 // Assume that all built-in displays that have secure output (eg. HDCP) also
184                 // support compositing from gralloc protected buffers.
185                 if (mPhys.secure) {
186                     mInfo.flags = DisplayDeviceInfo.FLAG_SECURE
187                             | DisplayDeviceInfo.FLAG_SUPPORTS_PROTECTED_BUFFERS;
188                 }
189
190                 if (mBuiltInDisplayId == SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN) {
191                     mInfo.name = getContext().getResources().getString(
192                             com.android.internal.R.string.display_manager_built_in_display_name);
193                     mInfo.flags |= DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY
194                             | DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT;
195                     mInfo.type = Display.TYPE_BUILT_IN;
196                     mInfo.densityDpi = (int)(mPhys.density * 160 + 0.5f);
197                     mInfo.xDpi = mPhys.xDpi;
198                     mInfo.yDpi = mPhys.yDpi;
199                     mInfo.touch = DisplayDeviceInfo.TOUCH_INTERNAL;
200                 } else {
201                     mInfo.type = Display.TYPE_HDMI;
202                     mInfo.flags |= DisplayDeviceInfo.FLAG_PRESENTATION;
203                     mInfo.name = getContext().getResources().getString(
204                             com.android.internal.R.string.display_manager_hdmi_display_name);
205                     mInfo.touch = DisplayDeviceInfo.TOUCH_EXTERNAL;
206                     mInfo.setAssumedDensityForExternalDisplay(mPhys.width, mPhys.height);
207
208                     // For demonstration purposes, allow rotation of the external display.
209                     // In the future we might allow the user to configure this directly.
210                     if ("portrait".equals(SystemProperties.get("persist.demo.hdmirotation"))) {
211                         mInfo.rotation = Surface.ROTATION_270;
212                     }
213
214                     // For demonstration purposes, allow rotation of the external display
215                     // to follow the built-in display.
216                     if (SystemProperties.getBoolean("persist.demo.hdmirotates", false)) {
217                         mInfo.flags |= DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT;
218                     }
219                 }
220             }
221             return mInfo;
222         }
223
224         @Override
225         public void requestDisplayStateLocked(int state) {
226             if (mState != state) {
227                 SurfaceControl.setDisplayPowerMode(getDisplayTokenLocked(),
228                         getPowerModeForState(state));
229                 mState = state;
230                 updateDeviceInfoLocked();
231             }
232         }
233
234         @Override
235         public void requestRefreshRateLocked(float refreshRate) {
236             if (mLastRequestedRefreshRate == refreshRate) {
237                 return;
238             }
239             mLastRequestedRefreshRate = refreshRate;
240             if (refreshRate != 0) {
241                 final int N = mSupportedRefreshRates.length;
242                 for (int i = 0; i < N; i++) {
243                     if (refreshRate == mSupportedRefreshRates[i]) {
244                         final int configIndex = mRefreshRateConfigIndices[i];
245                         SurfaceControl.setActiveConfig(getDisplayTokenLocked(), configIndex);
246                         return;
247                     }
248                 }
249                 Slog.w(TAG, "Requested refresh rate " + refreshRate + " is unsupported.");
250             }
251             SurfaceControl.setActiveConfig(getDisplayTokenLocked(), mDefaultPhysicalDisplayInfo);
252         }
253
254         @Override
255         public void dumpLocked(PrintWriter pw) {
256             super.dumpLocked(pw);
257             pw.println("mBuiltInDisplayId=" + mBuiltInDisplayId);
258             pw.println("mPhys=" + mPhys);
259             pw.println("mState=" + Display.stateToString(mState));
260         }
261
262         private void updateDeviceInfoLocked() {
263             mInfo = null;
264             sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED);
265         }
266
267         private void updateSupportedRefreshRatesLocked(
268                 SurfaceControl.PhysicalDisplayInfo[] physicalDisplayInfos,
269                 SurfaceControl.PhysicalDisplayInfo activePhys) {
270             final int N = physicalDisplayInfos.length;
271             int idx = 0;
272             mSupportedRefreshRates = new float[N];
273             mRefreshRateConfigIndices = new int[N];
274             for (int i = 0; i < N; i++) {
275                 final SurfaceControl.PhysicalDisplayInfo phys = physicalDisplayInfos[i];
276                 if (activePhys.width == phys.width
277                         && activePhys.height == phys.height
278                         && activePhys.density == phys.density
279                         && activePhys.xDpi == phys.xDpi
280                         && activePhys.yDpi == phys.yDpi) {
281                     mSupportedRefreshRates[idx] = phys.refreshRate;
282                     mRefreshRateConfigIndices[idx++] = i;
283                 }
284             }
285             if (idx != N) {
286                 mSupportedRefreshRates = Arrays.copyOfRange(mSupportedRefreshRates, 0, idx);
287                 mRefreshRateConfigIndices = Arrays.copyOfRange(mRefreshRateConfigIndices, 0, idx);
288             }
289         }
290     }
291
292     private final class HotplugDisplayEventReceiver extends DisplayEventReceiver {
293         public HotplugDisplayEventReceiver(Looper looper) {
294             super(looper);
295         }
296
297         @Override
298         public void onHotplug(long timestampNanos, int builtInDisplayId, boolean connected) {
299             synchronized (getSyncRoot()) {
300                 if (connected) {
301                     tryConnectDisplayLocked(builtInDisplayId);
302                 } else {
303                     tryDisconnectDisplayLocked(builtInDisplayId);
304                 }
305             }
306         }
307     }
308 }