LocalDisplayAdapter.java revision f0681b34dffc1510cbd9c3da5c3a7e695553fa8d
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 that have secure output (eg. HDCP) also 131 // support compositing from gralloc protected buffers. 132 if (mPhys.secure) { 133 mInfo.flags = DisplayDeviceInfo.FLAG_SECURE 134 | DisplayDeviceInfo.FLAG_SUPPORTS_PROTECTED_BUFFERS; 135 } 136 137 if (mBuiltInDisplayId == Surface.BUILT_IN_DISPLAY_ID_MAIN) { 138 mInfo.name = getContext().getResources().getString( 139 com.android.internal.R.string.display_manager_built_in_display_name); 140 mInfo.flags |= DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY 141 | DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT; 142 mInfo.densityDpi = (int)(mPhys.density * 160 + 0.5f); 143 mInfo.xDpi = mPhys.xDpi; 144 mInfo.yDpi = mPhys.yDpi; 145 mInfo.touch = DisplayDeviceInfo.TOUCH_INTERNAL; 146 } else { 147 mInfo.name = getContext().getResources().getString( 148 com.android.internal.R.string.display_manager_hdmi_display_name); 149 mInfo.touch = DisplayDeviceInfo.TOUCH_EXTERNAL; 150 mInfo.setAssumedDensityForExternalDisplay(mPhys.width, mPhys.height); 151 152 // For demonstration purposes, allow rotation of the external display. 153 // In the future we might allow the user to configure this directly. 154 if ("portrait".equals(SystemProperties.get("persist.demo.hdmirotation"))) { 155 mInfo.rotation = Surface.ROTATION_270; 156 } 157 } 158 } 159 return mInfo; 160 } 161 162 @Override 163 public void blankLocked() { 164 mBlanked = true; 165 Surface.blankDisplay(getDisplayTokenLocked()); 166 } 167 168 @Override 169 public void unblankLocked() { 170 mBlanked = false; 171 Surface.unblankDisplay(getDisplayTokenLocked()); 172 } 173 174 @Override 175 public void dumpLocked(PrintWriter pw) { 176 super.dumpLocked(pw); 177 pw.println("mBuiltInDisplayId=" + mBuiltInDisplayId); 178 pw.println("mPhys=" + mPhys); 179 pw.println("mBlanked=" + mBlanked); 180 } 181 } 182 183 private final class HotplugDisplayEventReceiver extends DisplayEventReceiver { 184 public HotplugDisplayEventReceiver(Looper looper) { 185 super(looper); 186 } 187 188 @Override 189 public void onHotplug(long timestampNanos, int builtInDisplayId, boolean connected) { 190 synchronized (getSyncRoot()) { 191 scanDisplaysLocked(); 192 } 193 } 194 } 195}