LocalDisplayAdapter.java revision 037c33eae74bee2774897d969d48947f9abe254f
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.SparseArray; 25import android.view.Display; 26import android.view.DisplayEventReceiver; 27import android.view.Surface; 28import android.view.SurfaceControl; 29import android.view.SurfaceControl.PhysicalDisplayInfo; 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 private final SurfaceControl.PhysicalDisplayInfo mTempPhys = new SurfaceControl.PhysicalDisplayInfo(); 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 && 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 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 int mState = Display.STATE_UNKNOWN; 106 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 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 124 public void applyPendingDisplayDeviceInfoChangesLocked() { 125 if (mHavePendingChanges) { 126 mInfo = null; 127 mHavePendingChanges = false; 128 } 129 } 130 131 @Override 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 mInfo.state = mState; 139 140 // Assume that all built-in displays that have secure output (eg. HDCP) also 141 // support compositing from gralloc protected buffers. 142 if (mPhys.secure) { 143 mInfo.flags = DisplayDeviceInfo.FLAG_SECURE 144 | DisplayDeviceInfo.FLAG_SUPPORTS_PROTECTED_BUFFERS; 145 } 146 147 if (mBuiltInDisplayId == SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN) { 148 mInfo.name = getContext().getResources().getString( 149 com.android.internal.R.string.display_manager_built_in_display_name); 150 mInfo.flags |= DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY 151 | DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT; 152 mInfo.type = Display.TYPE_BUILT_IN; 153 mInfo.densityDpi = (int)(mPhys.density * 160 + 0.5f); 154 mInfo.xDpi = mPhys.xDpi; 155 mInfo.yDpi = mPhys.yDpi; 156 mInfo.touch = DisplayDeviceInfo.TOUCH_INTERNAL; 157 } else { 158 mInfo.type = Display.TYPE_HDMI; 159 mInfo.flags |= DisplayDeviceInfo.FLAG_PRESENTATION; 160 mInfo.name = getContext().getResources().getString( 161 com.android.internal.R.string.display_manager_hdmi_display_name); 162 mInfo.touch = DisplayDeviceInfo.TOUCH_EXTERNAL; 163 mInfo.setAssumedDensityForExternalDisplay(mPhys.width, mPhys.height); 164 165 // For demonstration purposes, allow rotation of the external display. 166 // In the future we might allow the user to configure this directly. 167 if ("portrait".equals(SystemProperties.get("persist.demo.hdmirotation"))) { 168 mInfo.rotation = Surface.ROTATION_270; 169 } 170 } 171 } 172 return mInfo; 173 } 174 175 @Override 176 public void requestDisplayStateLocked(int state) { 177 if (mState != state) { 178 if (state == Display.STATE_OFF && mState != Display.STATE_OFF) { 179 SurfaceControl.blankDisplay(getDisplayTokenLocked()); 180 } else if (state != Display.STATE_OFF && mState == Display.STATE_OFF) { 181 SurfaceControl.unblankDisplay(getDisplayTokenLocked()); 182 } 183 mState = state; 184 updateDeviceInfoLocked(); 185 } 186 } 187 188 @Override 189 public void dumpLocked(PrintWriter pw) { 190 super.dumpLocked(pw); 191 pw.println("mBuiltInDisplayId=" + mBuiltInDisplayId); 192 pw.println("mPhys=" + mPhys); 193 pw.println("mState=" + Display.stateToString(mState)); 194 } 195 196 private void updateDeviceInfoLocked() { 197 mInfo = null; 198 sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED); 199 } 200 } 201 202 private final class HotplugDisplayEventReceiver extends DisplayEventReceiver { 203 public HotplugDisplayEventReceiver(Looper looper) { 204 super(looper); 205 } 206 207 @Override 208 public void onHotplug(long timestampNanos, int builtInDisplayId, boolean connected) { 209 synchronized (getSyncRoot()) { 210 if (connected) { 211 tryConnectDisplayLocked(builtInDisplayId); 212 } else { 213 tryDisconnectDisplayLocked(builtInDisplayId); 214 } 215 } 216 } 217 } 218}