LocalDisplayAdapter.java revision 5dc219142a756d57355b511c8f8ab913c01710da
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 17package com.android.server.display; 18 19import android.content.Context; 20import android.os.Handler; 21import android.os.IBinder; 22import android.os.Looper; 23import android.os.SystemProperties; 24import android.util.Slog; 25import android.util.SparseArray; 26import android.view.Display; 27import android.view.DisplayEventReceiver; 28import android.view.Surface; 29import android.view.SurfaceControl; 30 31import 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 */ 39final 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 // Called with SyncRoot lock held. 52 public LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot, 53 Context context, Handler handler, Listener listener) { 54 super(syncRoot, context, handler, listener, TAG); 55 } 56 57 @Override 58 public void registerLocked() { 59 super.registerLocked(); 60 61 mHotplugReceiver = new HotplugDisplayEventReceiver(getHandler().getLooper()); 62 63 for (int builtInDisplayId : BUILT_IN_DISPLAY_IDS_TO_SCAN) { 64 tryConnectDisplayLocked(builtInDisplayId); 65 } 66 } 67 68 private void tryConnectDisplayLocked(int builtInDisplayId) { 69 IBinder displayToken = SurfaceControl.getBuiltInDisplay(builtInDisplayId); 70 if (displayToken != null) { 71 SurfaceControl.PhysicalDisplayInfo[] configs = 72 SurfaceControl.getDisplayConfigs(displayToken); 73 if (configs == null) { 74 // There are no valid configs for this device, so we can't use it 75 Slog.w(TAG, "No valid configs found for display device " + 76 builtInDisplayId); 77 return; 78 } 79 int activeConfig = SurfaceControl.getActiveConfig(displayToken); 80 if (activeConfig < 0) { 81 // There is no active config, and for now we don't have the 82 // policy to set one. 83 Slog.w(TAG, "No active config found for display device " + 84 builtInDisplayId); 85 return; 86 } 87 LocalDisplayDevice device = mDevices.get(builtInDisplayId); 88 if (device == null) { 89 // Display was added. 90 device = new LocalDisplayDevice(displayToken, builtInDisplayId, 91 configs[activeConfig]); 92 mDevices.put(builtInDisplayId, device); 93 sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_ADDED); 94 } else if (device.updatePhysicalDisplayInfoLocked(configs[activeConfig])) { 95 // Display properties changed. 96 sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_CHANGED); 97 } 98 } else { 99 // The display is no longer available. Ignore the attempt to add it. 100 // If it was connected but has already been disconnected, we'll get a 101 // disconnect event that will remove it from mDevices. 102 } 103 } 104 105 private void tryDisconnectDisplayLocked(int builtInDisplayId) { 106 LocalDisplayDevice device = mDevices.get(builtInDisplayId); 107 if (device != null) { 108 // Display was removed. 109 mDevices.remove(builtInDisplayId); 110 sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_REMOVED); 111 } 112 } 113 114 static int getPowerModeForState(int state) { 115 switch (state) { 116 case Display.STATE_OFF: 117 return SurfaceControl.POWER_MODE_OFF; 118 case Display.STATE_DOZE: 119 return SurfaceControl.POWER_MODE_DOZE; 120 case Display.STATE_DOZE_SUSPEND: 121 return SurfaceControl.POWER_MODE_DOZE_SUSPEND; 122 default: 123 return SurfaceControl.POWER_MODE_NORMAL; 124 } 125 } 126 127 private final class LocalDisplayDevice extends DisplayDevice { 128 private final int mBuiltInDisplayId; 129 private final SurfaceControl.PhysicalDisplayInfo mPhys; 130 131 private DisplayDeviceInfo mInfo; 132 private boolean mHavePendingChanges; 133 private int mState = Display.STATE_UNKNOWN; 134 135 public LocalDisplayDevice(IBinder displayToken, int builtInDisplayId, 136 SurfaceControl.PhysicalDisplayInfo phys) { 137 super(LocalDisplayAdapter.this, displayToken); 138 mBuiltInDisplayId = builtInDisplayId; 139 mPhys = new SurfaceControl.PhysicalDisplayInfo(phys); 140 } 141 142 public boolean updatePhysicalDisplayInfoLocked(SurfaceControl.PhysicalDisplayInfo phys) { 143 if (!mPhys.equals(phys)) { 144 mPhys.copyFrom(phys); 145 mHavePendingChanges = true; 146 return true; 147 } 148 return false; 149 } 150 151 @Override 152 public void applyPendingDisplayDeviceInfoChangesLocked() { 153 if (mHavePendingChanges) { 154 mInfo = null; 155 mHavePendingChanges = false; 156 } 157 } 158 159 @Override 160 public DisplayDeviceInfo getDisplayDeviceInfoLocked() { 161 if (mInfo == null) { 162 mInfo = new DisplayDeviceInfo(); 163 mInfo.width = mPhys.width; 164 mInfo.height = mPhys.height; 165 mInfo.refreshRate = mPhys.refreshRate; 166 mInfo.appVsyncOffsetNanos = mPhys.appVsyncOffsetNanos; 167 mInfo.presentationDeadlineNanos = mPhys.presentationDeadlineNanos; 168 mInfo.state = mState; 169 170 // Assume that all built-in displays that have secure output (eg. HDCP) also 171 // support compositing from gralloc protected buffers. 172 if (mPhys.secure) { 173 mInfo.flags = DisplayDeviceInfo.FLAG_SECURE 174 | DisplayDeviceInfo.FLAG_SUPPORTS_PROTECTED_BUFFERS; 175 } 176 177 if (mBuiltInDisplayId == SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN) { 178 mInfo.name = getContext().getResources().getString( 179 com.android.internal.R.string.display_manager_built_in_display_name); 180 mInfo.flags |= DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY 181 | DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT; 182 mInfo.type = Display.TYPE_BUILT_IN; 183 mInfo.densityDpi = (int)(mPhys.density * 160 + 0.5f); 184 mInfo.xDpi = mPhys.xDpi; 185 mInfo.yDpi = mPhys.yDpi; 186 mInfo.touch = DisplayDeviceInfo.TOUCH_INTERNAL; 187 } else { 188 mInfo.type = Display.TYPE_HDMI; 189 mInfo.flags |= DisplayDeviceInfo.FLAG_PRESENTATION; 190 mInfo.name = getContext().getResources().getString( 191 com.android.internal.R.string.display_manager_hdmi_display_name); 192 mInfo.touch = DisplayDeviceInfo.TOUCH_EXTERNAL; 193 mInfo.setAssumedDensityForExternalDisplay(mPhys.width, mPhys.height); 194 195 // For demonstration purposes, allow rotation of the external display. 196 // In the future we might allow the user to configure this directly. 197 if ("portrait".equals(SystemProperties.get("persist.demo.hdmirotation"))) { 198 mInfo.rotation = Surface.ROTATION_270; 199 } 200 201 // For demonstration purposes, allow rotation of the external display 202 // to follow the built-in display. 203 if (SystemProperties.getBoolean("persist.demo.hdmirotates", false)) { 204 mInfo.flags |= DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT; 205 } 206 } 207 } 208 return mInfo; 209 } 210 211 @Override 212 public void requestDisplayStateLocked(int state) { 213 if (mState != state) { 214 SurfaceControl.setDisplayPowerMode(getDisplayTokenLocked(), 215 getPowerModeForState(state)); 216 mState = state; 217 updateDeviceInfoLocked(); 218 } 219 } 220 221 @Override 222 public void dumpLocked(PrintWriter pw) { 223 super.dumpLocked(pw); 224 pw.println("mBuiltInDisplayId=" + mBuiltInDisplayId); 225 pw.println("mPhys=" + mPhys); 226 pw.println("mState=" + Display.stateToString(mState)); 227 } 228 229 private void updateDeviceInfoLocked() { 230 mInfo = null; 231 sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED); 232 } 233 } 234 235 private final class HotplugDisplayEventReceiver extends DisplayEventReceiver { 236 public HotplugDisplayEventReceiver(Looper looper) { 237 super(looper); 238 } 239 240 @Override 241 public void onHotplug(long timestampNanos, int builtInDisplayId, boolean connected) { 242 synchronized (getSyncRoot()) { 243 if (connected) { 244 tryConnectDisplayLocked(builtInDisplayId); 245 } else { 246 tryDisconnectDisplayLocked(builtInDisplayId); 247 } 248 } 249 } 250 } 251} 252