LocalDisplayAdapter.java revision 77aebfdbae489c3712ae3f9bca29d01fb1f09dc2
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.util.SparseArray; 24import android.view.DisplayEventReceiver; 25import android.view.Surface; 26import android.view.Surface.PhysicalDisplayInfo; 27 28import java.io.PrintWriter; 29 30/** 31 * A display adapter for the local displays managed by Surface Flinger. 32 * <p> 33 * Display adapters are guarded by the {@link DisplayManagerService.SyncRoot} lock. 34 * </p> 35 */ 36final class LocalDisplayAdapter extends DisplayAdapter { 37 private static final String TAG = "LocalDisplayAdapter"; 38 39 private static final int[] BUILT_IN_DISPLAY_IDS_TO_SCAN = new int[] { 40 Surface.BUILT_IN_DISPLAY_ID_MAIN, 41 Surface.BUILT_IN_DISPLAY_ID_HDMI, 42 }; 43 44 private final SparseArray<LocalDisplayDevice> mDevices = 45 new SparseArray<LocalDisplayDevice>(); 46 private final HotplugDisplayEventReceiver mHotplugReceiver; 47 48 private final PhysicalDisplayInfo mTempPhys = new PhysicalDisplayInfo(); 49 50 public LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot, 51 Context context, Handler handler, Listener listener) { 52 super(syncRoot, context, handler, listener, TAG); 53 mHotplugReceiver = new HotplugDisplayEventReceiver(handler.getLooper()); 54 } 55 56 @Override 57 public void registerLocked() { 58 // TODO: listen for notifications from Surface Flinger about 59 // built-in displays being added or removed and rescan as needed. 60 super.registerLocked(); 61 scanDisplaysLocked(); 62 } 63 64 private void scanDisplaysLocked() { 65 for (int builtInDisplayId : BUILT_IN_DISPLAY_IDS_TO_SCAN) { 66 IBinder displayToken = Surface.getBuiltInDisplay(builtInDisplayId); 67 if (displayToken != null && Surface.getDisplayInfo(displayToken, mTempPhys)) { 68 LocalDisplayDevice device = mDevices.get(builtInDisplayId); 69 if (device == null) { 70 // Display was added. 71 device = new LocalDisplayDevice(displayToken, builtInDisplayId, mTempPhys); 72 mDevices.put(builtInDisplayId, device); 73 sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_ADDED); 74 } else if (device.updatePhysicalDisplayInfoLocked(mTempPhys)) { 75 // Display properties changed. 76 sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_CHANGED); 77 } 78 } else { 79 LocalDisplayDevice device = mDevices.get(builtInDisplayId); 80 if (device != null) { 81 // Display was removed. 82 mDevices.remove(builtInDisplayId); 83 sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_REMOVED); 84 } 85 } 86 } 87 } 88 89 private final class LocalDisplayDevice extends DisplayDevice { 90 private final int mBuiltInDisplayId; 91 private final PhysicalDisplayInfo mPhys; 92 93 private DisplayDeviceInfo mInfo; 94 private boolean mHavePendingChanges; 95 96 public LocalDisplayDevice(IBinder displayToken, int builtInDisplayId, 97 PhysicalDisplayInfo phys) { 98 super(LocalDisplayAdapter.this, displayToken); 99 mBuiltInDisplayId = builtInDisplayId; 100 mPhys = new PhysicalDisplayInfo(phys); 101 } 102 103 public boolean updatePhysicalDisplayInfoLocked(PhysicalDisplayInfo phys) { 104 if (!mPhys.equals(phys)) { 105 mPhys.copyFrom(phys); 106 mHavePendingChanges = true; 107 return true; 108 } 109 return false; 110 } 111 112 @Override 113 public void applyPendingDisplayDeviceInfoChangesLocked() { 114 if (mHavePendingChanges) { 115 mInfo = null; 116 mHavePendingChanges = false; 117 } 118 } 119 120 @Override 121 public DisplayDeviceInfo getDisplayDeviceInfoLocked() { 122 if (mInfo == null) { 123 mInfo = new DisplayDeviceInfo(); 124 mInfo.width = mPhys.width; 125 mInfo.height = mPhys.height; 126 mInfo.refreshRate = mPhys.refreshRate; 127 128 // Assume that all built-in displays have secure output (eg. HDCP) and 129 // support compositing from gralloc protected buffers. 130 mInfo.flags = DisplayDeviceInfo.FLAG_SECURE 131 | DisplayDeviceInfo.FLAG_SUPPORTS_PROTECTED_BUFFERS; 132 133 if (mBuiltInDisplayId == Surface.BUILT_IN_DISPLAY_ID_MAIN) { 134 mInfo.name = getContext().getResources().getString( 135 com.android.internal.R.string.display_manager_built_in_display_name); 136 mInfo.flags |= DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY 137 | DisplayDeviceInfo.FLAG_SUPPORTS_ROTATION; 138 mInfo.densityDpi = (int)(mPhys.density * 160 + 0.5f); 139 mInfo.xDpi = mPhys.xDpi; 140 mInfo.yDpi = mPhys.yDpi; 141 mInfo.touch = DisplayDeviceInfo.TOUCH_INTERNAL; 142 } else { 143 mInfo.name = getContext().getResources().getString( 144 com.android.internal.R.string.display_manager_hdmi_display_name); 145 mInfo.touch = DisplayDeviceInfo.TOUCH_EXTERNAL; 146 mInfo.setAssumedDensityForExternalDisplay(mPhys.width, mPhys.height); 147 } 148 } 149 return mInfo; 150 } 151 152 @Override 153 public void dumpLocked(PrintWriter pw) { 154 super.dumpLocked(pw); 155 pw.println("mBuiltInDisplayId=" + mBuiltInDisplayId); 156 pw.println("mPhys=" + mPhys); 157 } 158 } 159 160 private final class HotplugDisplayEventReceiver extends DisplayEventReceiver { 161 public HotplugDisplayEventReceiver(Looper looper) { 162 super(looper); 163 } 164 165 @Override 166 public void onHotplug(long timestampNanos, int builtInDisplayId, boolean connected) { 167 synchronized (getSyncRoot()) { 168 scanDisplaysLocked(); 169 } 170 } 171 } 172}