HDMI框架层控制部分别在两个部分:
frameworks/base/core/java/android/hardware/hdmi
frameworks/base/services/core/java/com/android/server/hdmi
如果平台是MTK的,
有会一个frameworks/base/services/core/java/com/mediatek/hdmi/MtkHdmiManagerService.java 类,此类有详细的执行操作,此文不做多的解释,
HDMI 首先在PhoneWindowManager中初始化状态
void initializeHdmiState() {
boolean plugged = false;
// watch for HDMI plug messages if the hdmi switch exists
if (new File("/sys/devices/virtual/switch/hdmi/state").exists()) {
mHDMIObserver.startObserving("DEVPATH=/devices/virtual/switch/hdmi");
final String filename = "/sys/class/switch/hdmi/state";
FileReader reader = null;
try {
reader = new FileReader(filename);
char[] buf = new char[15];
int n = reader.read(buf);
if (n > 1) {
plugged = 0 != Integer.parseInt(new String(buf, 0, n-1));
}
} catch (IOException ex) {
Slog.w(TAG, "Couldn't read hdmi state from " + filename + ": " + ex);
} catch (NumberFormatException ex) {
Slog.w(TAG, "Couldn't read hdmi state from " + filename + ": " + ex);
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException ex) {
}
}
}
}
// This dance forces the code in setHdmiPlugged to run.
// Always do this so the sticky intent is stuck (to false) if there is no hdmi.
mHdmiPlugged = !plugged;
setHdmiPlugged(!mHdmiPlugged);
}
就是去读state文件,如果连接了电视机则其值为:1,未连接则其值为:0
另外下面代码处是监听HDMI状态值的变化
private UEventObserver mHDMIObserver = new UEventObserver() {
@Override
public void onUEvent(UEventObserver.UEvent event) {
setHdmiPlugged("1".equals(event.get("SWITCH_STATE")));
}
};
在PhoneWindowManager.java::setInitialDisplaySize()中
SystemProperties.get("persist.demo.hdmirotation")) 是否允许HDMI连接后,竖屏显示,默认空
mDemoHdmiRotationLock = SystemProperties.getBoolean("persist.demo.hdmirotationlock", false); 固定屏幕方向默认false,
如果固定HDMI连接屏的显示方向,则会执行下面的执行,
else if (mHdmiPlugged && mDemoHdmiRotationLock) {
// Ignore sensor when plugged into HDMI when demo HDMI rotation lock enabled.
// Note that the dock orientation overrides the HDMI orientation.
preferredRotation = mDemoHdmiRotation;
}
mHdmiPlugged 状态为当前机器是否有HDMI连接设备,当前有连接则为true,反之则为false,
HDMIl连接设备对象的信息则是在frameworks\base\services\core\java\com\android\server\display\LocalDisplayAdapter.java中getDisplayDeviceInfoLocked()方法的中的else部分逻辑中生成
mInfo.type = Display.TYPE_HDMI;
mInfo.flags |= DisplayDeviceInfo.FLAG_PRESENTATION;
mInfo.name = getContext().getResources().getString(
com.android.internal.R.string.display_manager_hdmi_display_name);
mInfo.touch = DisplayDeviceInfo.TOUCH_EXTERNAL;
mInfo.setAssumedDensityForExternalDisplay(phys.width, phys.height);
// For demonstration purposes, allow rotation of the external display.
// In the future we might allow the user to configure this directly.
if ("portrait".equals(SystemProperties.get("persist.demo.hdmirotation"))) {
mInfo.rotation = Surface.ROTATION_270;
}
// For demonstration purposes, allow rotation of the external display
// to follow the built-in display.
if (SystemProperties.getBoolean("persist.demo.hdmirotates", false)) {
mInfo.flags |= DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT;
}
if (!res.getBoolean(
com.android.internal.R.bool.config_localDisplaysMirrorContent)) {
mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY;
}
另外再看看此类的registerLocked方法
@Override
public void registerLocked() {
super.registerLocked();
mHotplugReceiver = new HotplugDisplayEventReceiver(getHandler().getLooper());
for (int builtInDisplayId : BUILT_IN_DISPLAY_IDS_TO_SCAN) {
tryConnectDisplayLocked(builtInDisplayId);
}
}
BUILD_IN 跟HDMI,built_in可以理解成默认的显示屏,比如手机中默认的MIPI屏,而HDMI则是扩展屏(如电视机),目前在手机上集成HDMI接口的貌似不多,但是usb type c流行后,通过type c来扩展屏幕可能不少,这可能会是一个新的手机定制需求。
private static final int[] BUILT_IN_DISPLAY_IDS_TO_SCAN = new int[] {
SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN,
SurfaceControl.BUILT_IN_DISPLAY_ID_HDMI,
};
DMS中有很多类型的的DisplayAdapter
LocalDisplayAdapter是针对本地已经存在的物理显示屏设备(即HDMI显示)。
WifiDisplayAdapter针对WiFi Display
OverlayDisplayAdapter (这个悬浮显示,在设置-开发者选项-悬浮显示)
VirtualDisplayAdapter 显示一个虚拟屏幕,该功能可以在开发者选项中开启,可以去研究下这个,
DisplayManagerService.java中DMS服务启动之时onStart函数会被调用,这个函数中会外发一个MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER的消息。
@Override
public void onStart() {
// We need to pre-load the persistent data store so it's ready before the default display
// adapter is up so that we have it's configuration. We could load it lazily, but since
// we're going to have to read it in eventually we may as well do it here rather than after
// we've waited for the diplay to register itself with us.
mPersistentDataStore.loadIfNeeded();
mHandler.sendEmptyMessage(MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER);
publishBinderService(Context.DISPLAY_SERVICE, new BinderService(),
true /*allowIsolated*/);
publishLocalService(DisplayManagerInternal.class, new LocalService());
publishLocalService(DisplayTransformManager.class, new DisplayTransformManager());
}
private void registerDefaultDisplayAdapter() {
// Register default display adapter.
synchronized (mSyncRoot) {
registerDisplayAdapterLocked(new LocalDisplayAdapter(//构建一个LocalDisplayAdapter
mSyncRoot, mContext, mHandler, mDisplayAdapterListener));
}
}
其它文献: