Android HDMI( 三)
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)); } }
其它文献:
android graphic(12)—display上层相关概念、关系
Android Display 系统分析
Android Display的初始化
如何获取显示器的EDID信息
Andrdoid6.0 DisplayManagerService
更多相关文章
- Android虚拟机大屏幕设置
- Android adb获取屏幕分辨率
- Android 获取状态栏的高度
- android 中超出屏幕宽度的字符 省略号显示
- Android 沉浸式状态栏实现,以及遇到的问题
- Android沉浸式状态栏和手机虚拟按钮不兼容冲突的
- webview开发-适配多分辨率的Android设备