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