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