android hdmi 开发,Android TV HDMI开发

文章目录

一、分辨率

1.1、获取/设置分辨率

1.2、初始化默认分辨率

1.2.1、最优分辨率

1.2.2、最大分辨率

二、电视机信息

三、待机

在进行机顶盒ROM开发时,HDMI相关功能是常见的功能模块,本篇文章就简单介绍一些常见的HDMI相关需求开发。

常见的HDMI相关功能可分为三大块:(通过HDMI线获取/设置)分辨率、(通过HDMI线获取)电视机信息、(HDMI)待机。

一、分辨率

机顶盒通过HDMI线与TV相连时,是通过HDMI线(获取TV的EDID)来获取TV支持的分辨率情况的,所以与此相关的功能有获取/设置分辨率、初始化默认分辨率等。

1.1、获取/设置分辨率

该功能的相关代码代码看上去和HDMI“没多大关系”,属于Android通用性功能,其实不然,该功能与HDMI息息相关。接下来就以Hi3798MV300和Amlogic905两种平台来简单介绍。

先以Hi3798MV300为例,获取分辨率用到的接口和Android原生流程是一样的,主要来自于frameworks/base/core/java/android/os/display/DisplayManager.java,关键接口如下:

private int[] mAllDisplayStandard = {

DISPLAY_STANDARD_1080P_60,

DISPLAY_STANDARD_1080P_50,

DISPLAY_STANDARD_1080P_30,

DISPLAY_STANDARD_1080P_25,

DISPLAY_STANDARD_1080P_24,

DISPLAY_STANDARD_1080I_60,

DISPLAY_STANDARD_1080I_50,

DISPLAY_STANDARD_720P_60,

DISPLAY_STANDARD_720P_50,

DISPLAY_STANDARD_576P_50,

DISPLAY_STANDARD_480P_60,

DISPLAY_STANDARD_PAL,

DISPLAY_STANDARD_NTSC,

DISPLAY_STANDARD_3840_2160P_24,

DISPLAY_STANDARD_3840_2160P_25,

DISPLAY_STANDARD_3840_2160P_30,

DISPLAY_STANDARD_3840_2160P_50,

DISPLAY_STANDARD_3840_2160P_60,

DISPLAY_STANDARD_4096_2160P_24,

DISPLAY_STANDARD_4096_2160P_25,

DISPLAY_STANDARD_4096_2160P_30,

DISPLAY_STANDARD_4096_2160P_50,

DISPLAY_STANDARD_4096_2160P_60,

};

public DisplayManager(IDisplayManager server) {

mdisplay = server;

//see display.c::get_hdmi_capability

// hisi format value fmt cap index

mMapEncFmtToIndex.put(ENC_FMT_1080P_60 , 1 );

mMapEncFmtToIndex.put(ENC_FMT_1080P_50 , 2 );

mMapEncFmtToIndex.put(ENC_FMT_1080P_30 , 3 );

mMapEncFmtToIndex.put(ENC_FMT_1080P_25 , 4 );

mMapEncFmtToIndex.put(ENC_FMT_1080P_24 , 5 );

mMapEncFmtToIndex.put(ENC_FMT_1080i_60 , 6 );

mMapEncFmtToIndex.put(ENC_FMT_1080i_50 , 7 );

mMapEncFmtToIndex.put(ENC_FMT_720P_60 , 8 );

mMapEncFmtToIndex.put(ENC_FMT_720P_50 , 9 );

mMapEncFmtToIndex.put(ENC_FMT_576P_50 , 10);

mMapEncFmtToIndex.put(ENC_FMT_480P_60 , 11);

mMapEncFmtToIndex.put(ENC_FMT_PAL , 12);

mMapEncFmtToIndex.put(ENC_FMT_NTSC , 15);

mMapEncFmtToIndex.put(ENC_FMT_3840x2160_24 , 44);

mMapEncFmtToIndex.put(ENC_FMT_3840x2160_25 , 45);

mMapEncFmtToIndex.put(ENC_FMT_3840x2160_30 , 46);

mMapEncFmtToIndex.put(ENC_FMT_3840x2160_50 , 47);

mMapEncFmtToIndex.put(ENC_FMT_3840x2160_60 , 48);

mMapEncFmtToIndex.put(ENC_FMT_4096X2160_24 , 49);

mMapEncFmtToIndex.put(ENC_FMT_4096X2160_25 , 50);

mMapEncFmtToIndex.put(ENC_FMT_4096X2160_30 , 51);

mMapEncFmtToIndex.put(ENC_FMT_4096X2160_50 , 52);

mMapEncFmtToIndex.put(ENC_FMT_4096X2160_60 , 53);

try{

int[] dispCapability = mdisplay.getDisplayCapability();

for(int i = 0; i < dispCapability.length; i++){

Log.d("DisplayManager.java", "dispCapability[" + i + "]=" + dispCapability[i]);

}

if(dispCapability != null){

int supportFmtCnt = 0;

int[] supportFmt = new int[mAllDisplayStandard.length];

for(int i = 0; i < mAllDisplayStandard.length; i++){

if(dispCapability[mMapEncFmtToIndex.get(covertCMCCFmtToHisi(mAllDisplayStandard[i]))] == 1){

supportFmt[supportFmtCnt] = mAllDisplayStandard[i];

supportFmtCnt++;

Log.d("DisplayManager.java", "supportFmt:" + mAllDisplayStandard[i]);

}

Log.d("DisplayManager.java", "supportFmtCnt:" + supportFmtCnt);

}

mStandard = new int[supportFmtCnt];

System.arraycopy(supportFmt, 0, mStandard, 0, supportFmtCnt);

}else{

mStandard = new int[0];

}

}

catch(Exception ex){

mStandard = new int[0];

}

}

public int[] getAllSupportStandards() {

return mStandard;

}

public boolean isSupportStandard(int standard) {

boolean ret = false;

for (int i = 0; i < mStandard.length; i++) {

if(standard == mStandard[i]){

ret = true;

break;

}

}

return ret;

}

public void setDisplayStandard(int standard) {

int hisiFmt = -1;

int ret = -1;

if(isSupportStandard(standard)){

try {

hisiFmt = covertCMCCFmtToHisi(standard);

if (hisiFmt >= ENC_FMT_1080P_60) {

ret = mdisplay.setFmt(hisiFmt);

}

} catch(Exception ex) {

Log.e(TAG,"setDisplayStandard: " + ex);

}

} else {

Log.e(TAG, "setDisplayStandard: unsupport(" + standard + ")");

}

Log.i(TAG, "setDisplayStandard: standard=" + standard + ", ret=" + ret);

}

public int getCurrentStandard() {

int hisiFmt = -1;

int cmccFmt = -1;

try {

hisiFmt = mdisplay.getFmt();

cmccFmt = covertHisiFmtToCMCC(hisiFmt);

} catch (RemoteException e) {

Log.e(TAG, "getCurrentStandard: " + e);

}

if(isSupportStandard(cmccFmt)){

return cmccFmt;

} else {

Log.e(TAG, "getCurrentStandard: CMCC unsupport(" + hisiFmt + ")");

return -1;

}

}

在Hi3798MV300上,使用以上接口,再结合一些其他的HDMI功能,就可以实现一个较为复杂的需求,比如:将机顶盒上的HDMI线连接到某一TV,判断该TV是否支持4K分辨率,如果支持,则切换到4K分辨率,否则不处理。关键代码示例如下:

private BroadcastReceiver mHdmiReceiver = new BroadcastReceiver() {

@Override

public void onReceive(Context context, Intent intent) {

String action = intent.getAction();

if (action.equals("android.intent.action.HDMI_PLUGGED")) {

boolean state = intent.getBooleanExtra("state", false);

Log.d(TAG,"HDMI status:"+state+",getHdmiSwitchSet():"+getHdmiSwitchSet());

if (state && getHdmiSwitchSet()) {

checkTVResolution();

}

}

}

};

private void checkTVResolution(){

int DISPLAY_STANDARD_3840_2160P_24 = 256;

boolean is4kResolutionSupported = false;

int[] supportList = mDisplayManager.getAllSupportStandards();

Arrays.sort(supportList);

for(int i=0;i

Log.d(TAG,"supportList["+i+"]:"+supportList[i]);

if(supportList[i] >= DISPLAY_STANDARD_3840_2160P_24){

is4kResolutionSupported = true;

break;

}

}

if(is4kResolutionSupported){

int best4kResolution = 260;

if(supportList[supportList.length-1] >= 260)

best4kResolution = 260;

mDisplayManager.setDisplayStandard(best4kResolution);

mDisplayManager.saveParams();

}

}

private static boolean getHdmiSwitchSet() {

File switchFile = new File("/sys/devices/virtual/switch/hdmi/state");

if (!switchFile.exists()) {

switchFile = new File("/sys/class/switch/hdmi/state");

}

try {

Scanner switchFileScanner = new Scanner(switchFile);

int switchValue = switchFileScanner.nextInt();

switchFileScanner.close();

return switchValue > 0;

} catch (Exception e) {

return false;

}

}

在Amlogic905上,用的不是原生的DisplayManager来处理分辨率,有一套别的实现方式,主要实现代码在frameworks/base/services/java/com/android/server/MboxOutputModeService.java,关键接口如下:

public String getSupportResoulutionList() {

if (isHDMIPlugged()) {

ArrayList mOutputModeList = readSupportList();

Slog.w(TAG, "getSupportResoulutionList error, output list is null!");

return null;

}

}

private ArrayList readSupportList() {

String str = null;

ArrayList mOutputModeList = new ArrayList();

try {

FileReader fr = new FileReader(HDMI_SUPPORT_LIST_SYSFS);//HDMI_SUPPORT_LIST_SYSFS = /sys/class/amhdmitx/amhdmitx0/disp_cap

BufferedReader br = new BufferedReader(fr);

try {

while ((str = br.readLine()) != null) {

if(str != null){

//if(DEBUG) Slog.i(TAG, "Output: " + str);

boolean filter = false;

OutputMode output = new OutputMode();

if(str.contains("null edid")) {

Slog.w(TAG, "readSupportList error, disp_cap: " + str);

return null;

}

if(str.contains("*")) {

output.mode = new String(str.substring(0, str.length()-1));

output.isBestMode = true;

} else {

output.mode = new String(str);

output.isBestMode = false;

}

//if(DEBUG) Slog.i(TAG, "readSupportList, Output: " + output.mode + ", isBestMode: " + output.isBestMode);

if(isOutputFilter(output.mode)) {

Slog.w(TAG, "readSupportList, filter this mode: " + output.mode);

} else {

mOutputModeList.add(output);

}

}

};

fr.close();

br.close();

return resolutionSort(mOutputModeList);

} catch (IOException e) {

e.printStackTrace();

return null;

}

} catch (FileNotFoundException e) {

e.printStackTrace();

return null;

}

}

public String getCurrentOutPutMode() {

String curMode = readSysfs(OutputModeFile);//OutputModeFile = "/sys/class/display/mode"

Slog.e(TAG,"getCurrentOutPutMode:" + curMode);

return curMode;

}

从上面的代码可以大致看出Amlogic905在分辨率方面的代码特征,即把相关信息存储在不同的节点中。

1.2、初始化默认分辨率

机顶盒设置的初始分辨率策略,一般有两种:最优分辨率与最大分辨率。

1.2.1、最优分辨率

此处的最优并不是TV支持的最大分辨率,而是ROM评估出来的、适合的一个分辨率,一般为720P或1080P,该策略一般也是ROM中的默认设置。

先以Hi3798MV300为例,该策略的主要实现代码在device/hisilicon/bigfish/frameworks/hidisplaymanager/hal/hi_adp_hdmi.c,以Hdmicap_NativeFormat_Strategy方法为例,关键代码如下:

else if (strcmp("p50hz", perfer) == 0)

{

if (HI_TRUE == is_format_support(&stSinkCap,HI_UNF_ENC_FMT_4096X2160_50))

{

stSinkCap.enNativeFormat = HI_UNF_ENC_FMT_4096X2160_50;

}

else if (HI_TRUE == is_format_support(&stSinkCap,HI_UNF_ENC_FMT_4096X2160_25))

{

stSinkCap.enNativeFormat = HI_UNF_ENC_FMT_4096X2160_25;

}

//since tv capability is upgrade now , add max fmt lever to 3840x2160 P50

else if (HI_TRUE == is_format_support(&stSinkCap,HI_UNF_ENC_FMT_3840x2160_50))

{

stSinkCap.enNativeFormat = HI_UNF_ENC_FMT_3840x2160_50;

}

else if (HI_TRUE == is_format_support(&stSinkCap,HI_UNF_ENC_FMT_3840x2160_25))

{

stSinkCap.enNativeFormat = HI_UNF_ENC_FMT_3840x2160_25;

}

else if (HI_TRUE == is_format_support(&stSinkCap,HI_UNF_ENC_FMT_1080P_50))

{

stSinkCap.enNativeFormat = HI_UNF_ENC_FMT_1080P_50;

}

else if (HI_TRUE == is_format_support(&stSinkCap,HI_UNF_ENC_FMT_720P_50))

{

stSinkCap.enNativeFormat = HI_UNF_ENC_FMT_720P_50;

}

else //if(stSinkCap.enNativeFormat = HI_UNF_ENC_FMT_576P_50)

{

ALOGI("Lowest default to 576p");

stSinkCap.enNativeFormat = HI_UNF_ENC_FMT_576P_50;

}

}

该段代码中,is_format_support函数是芯片的最优分辨率策略实现函数,一般当persist.sys.optimalfmt.perfer设置为"p50hz"时,默认分辨率是720P50hz。

Amlogic905的最优分辨率的实现方式也较为底层,framework层代码(frameworks/base/services/java/com/android/server/MboxOutputModeService.java)是根据节点的值来实现的,具体如下:

public String getBestMatchResolution() {

ArrayList mOutputModeList = readSupportList();

if (mOutputModeList != null && isHDMIPlugged()){

int size = mOutputModeList.size();

if(DEBUG) Slog.i(TAG, "getBestMatchResolution, output size: " + size);

for (int index = 0; index < size; index++) {

OutputMode output = mOutputModeList.get(index);

if (DEBUG) Slog.i(TAG,"getBestMatchResolution, output: " + output.mode + " isBestMode: " + output.isBestMode);

if (output.isBestMode) {

Slog.i(TAG, "getBestMatchResolution, return best mode: " + output.mode);

return output.mode;

}

}

}else if(!isHDMIPlugged()){

return "576cvbs";

}

String default_mode = getPropertyString("ro.platform.best_outputmode", DEFAULT_OUTPUT_MODE);

Slog.w(TAG, "getBestMatchResolution, return defalut outputmode: " + default_mode);

return default_mode;

}

Amlogic905方案中,当前TV所支持的分辨率列表是写在/sys/class/amhdmitx/amhdmitx0/disp_cap节点的,该节点值示例如下:

480i60hz

480p60hz

576i50hz

576p50hz

720p60hz

1080i60hz

1080p60hz*

720p50hz

1080i50hz

1080p50hz

1080p24hz

从上述内容可以看出所有支持的分辨率。其中后面加"*"符号的分辨率(该例子中的1080p60hz)就是系统默认的最适合分辨率,对应到代码中就是该分辨率对应的output.isBestMode为true。

1.2.2、最大分辨率

除了系统的默认最优分辨率策略,现在也常常使用最大分辨率策略,即自适应到当前TV支持的最大分辨率,该功能主要针对的是4K电视,在连接TV时,可以自适应到4K分辨率。

先以Hi3798MV300为例,自适应到最大分辨率,设置两个属性即可:

persist.sys.optimalfmt.enable=1

persist.sys.optimalfmt.perfer=max_fmt

persist.sys.optimalfmt.enable属性代表的意思是分辨率自适应开关,当该属性设置为1时,代表自适应分辨率功能打开;设置为0时,代表关闭。persist.sys.optimalfmt.perfer属性设置为max_fmt,即代表自适应到最高分辨率。该功能涉及的代码为device/hisilicon/bigfish/frameworks/hidisplaymanager/hal/hi_adp_hdmi.c,相关代码如下:

else if (0 == strcmp("max_fmt", perfer))

{

stSinkCap.enNativeFormat = getCurrentMaxSupportFmt();

}

HI_S32 getCurrentMaxSupportFmt()

{

HI_S32 listCount = 0;

HI_S32 MaxFmtListLen = 0;

HI_BOOL bSupport = HI_FALSE;

MaxFmtListLen = sizeof(HDMI_TV_MAX_SUPPORT_FMT) / sizeof(HDMI_TV_MAX_SUPPORT_FMT[0]);

ALOGI("MaxFmtListLen = %d", MaxFmtListLen);

for (listCount = 0; listCount < MaxFmtListLen; listCount++)

{

if (HI_TRUE == is_format_support(&stSinkCap,HDMI_TV_MAX_SUPPORT_FMT[listCount]))

{

ALOGI("max support fmt is:%d",HDMI_TV_MAX_SUPPORT_FMT[listCount]);

return HDMI_TV_MAX_SUPPORT_FMT[listCount];

}

}

ALOGI("Can't Find Max Support Format, getCurrentMaxFormat return:720P_50 !");

return HI_UNF_ENC_FMT_720P_50;

}

在Hi3798MV300上,除了直接设置上述两个属性外,还可以在上层应用实现自适应4K功能,相关代码参考1.1章节。

在Amlogic905上,可以在frameworks/base/services/java/com/android/server/MboxOutputModeService.java中的getBestMatchResolution中直接遍历所有分辨率,返回最大分辨率即可。

二、电视机信息

除了第一节提到的分辨率相关功能,还可以获取到TV相关信息,如型号、品牌等。

以Hi3798MV300为例,对于TV信息的获取是在底层做的,对于的代码为device/hisilicon/bigfish/frameworks/hidisplaymanager/hal/hi_adp_hdmi.c,关键代码如下:

void setTVproperty(display_format_e format)

{

int w = 0;

int h = 0;

int newhdrsuport = 2;

int oldhdrsport = 2;

char hei[5] ={0};

char dpi[15] = {0};

char size[10] = {0};

char buffer[BUFLEN] = {0};

framebuffer_get_max_screen_resolution(format,&w,&h);

ALOGI("format %d , w: %d ,h: %d,",format, w, h);

sprintf(dpi, "%d", w);

strcat(dpi,"*");

sprintf(hei, "%d", h);

strcat(dpi,hei);

ALOGI("dpi: %s", dpi);

sprintf(size,"%d",(int)(sqrt(TVHMax*TVHMax +TVWMax*TVWMax)/2.54 +0.5));

ALOGE("TVWidth:%d,Height:%d,TVSzie:%s", TVWMax, TVHMax, size);

property_set("persist.sys.tv.name",stSinkCap.stMfrsInfo.u8MfrsName); //代表电视机的品牌

property_set("persist.sys.tv.type",stSinkCap.stMfrsInfo.u8pSinkName); //代表电视机的具体型号

property_set("persist.sys.tv.size",size); //代表电视机的尺寸,即电视机对角线长度

property_set("persist.sys.tv.dpi",dpi); //代表电视机DPI,即每英寸像素点数

memset(buffer, 0, sizeof(buffer));

property_get("persist.sys.tv.Supporthdr", buffer , "2");

oldhdrsport = atoi(buffer);

if(HI_TRUE == stSinkCap.bHdrSupport && stSinkCap.stHdr.stEotf.bEotfSmpteSt2084)

newhdrsuport = 1;//yes 1

else if (HI_FALSE == stSinkCap.bHdrSupport)

newhdrsuport = 2;//no 2

else

newhdrsuport = 0;//other 0

//HSCP2018042722609

if(newhdrsuport != oldhdrsport)

{

sprintf(buffer, "%d", newhdrsuport);

property_set("persist.sys.tv.Supporthdr",buffer);

}

}

在Amlogic905上,电视机相关的信息是写在节点sys/class/amhdmitx/amhdmitx0/edid里的,示例内容如下:

Rx Brand Name: PHL

Rx Product Name: PHILIPS

Physcial size(cm): 52 x 29

Manufacture Week: 1

Manufacture Year: 2015

EDID Verison: 1.3

EDID block number: 0x1

blk0 chksum: 0x2c

Source Physical Address[a.b.c.d]: 1.0.0.0

native Mode f1, VIC (native 16):

ColorDeepSupport 2

31 16 20 5 19 4 2 3 32 22 18 6 7 1

Audio {format, channel, freq, cce}

{1, 1, 7, 7}

{10, 7, 6, 0}

Speaker Allocation: 1

Vendor: 0xc03

MaxTMDSClock1 290 MHz

SCDC: 0

RR_Cap: 0

LTE_340M_Scramble: 0

checkvalue: 0x2cc80000

Rx Brand Name代表的是电视机品牌;Rx Product Name代表的是电视机型号;Physcial size(cm)代表的是电视机长宽。

三、待机

此处主要的指的是"HDMI待机"功能,即电视机关机,机顶盒也跟着待机。

在Hi3798MV300上,一般设置两个属性即可:

persist.hdmi.suspend.enable = 1

persist.hdmi.suspend.time = 5

persist.hdmi.suspend.enable属性值代表HDMI待机开关,0代表关闭,1代表打开。persist.hdmi.suspend.time属性值代表待机时间,即电视机关机后多久,机顶盒进入待机,单位为分钟。该功能的实现也在device/hisilicon/bigfish/frameworks/hidisplaymanager/hal/hi_adp_hdmi.c,待机代码如下:

void HDMI_Suspend_Timeout()

{

ALOGI("HDMI_Suspend_Timeout: hdmi connect status flag hdmi_enable =%d",hdmi_enable);

char buffer[BUFLEN] = {0};

HI_UNF_HDMI_STATUS_S hdmiStatus;

//icsl init

hdmiStatus.bConnected = HI_FALSE;

HI_U8 is_under_cec_suspend = get_HDMI_CEC_Suspend_Status();

HI_UNF_HDMI_GetStatus(0,&hdmiStatus);

ALOGI("hdmiStatus.bConnected =%d",hdmiStatus.bConnected);

//hdmi uplug or hdmi rsen disconnect event suspend time out, send a power key to system

//end by lizheng 20190326 to solve 32a suspend

HDMI_Suspend_ReportKeyEvent(KEY_POWER, KPC_EV_KEY_PRESS);

HDMI_Suspend_ReportKeyEvent(KEY_POWER, KPC_EV_KEY_RELEASE);

ALOGW("\033[31mHDMI_Suspend_Timeout: send power key to suspend \33[0m\n");

property_get("ro.product.target", buffer, "0");

if(strcmp(buffer,"shcmcc")==0)

{

sleep(4);//unit : second

HDMI_Suspend_ReportKeyEvent(KEY_RIGHT, KPC_EV_KEY_PRESS);

HDMI_Suspend_ReportKeyEvent(KEY_RIGHT, KPC_EV_KEY_RELEASE);

sleep(2);

HDMI_Suspend_ReportKeyEvent(KEY_ENTER, KPC_EV_KEY_PRESS);

HDMI_Suspend_ReportKeyEvent(KEY_ENTER, KPC_EV_KEY_RELEASE);

}

}

从上面代码可以看出,进行机顶盒待机功能是通过模拟电源键按键操作来实现的。

在Amlogic905上,HDMI待机功能是在frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java中实现的。简单流程为,在init函数中,初始化HDMI相关的信息,代码如下:

void initializeHdmiState() {

boolean plugged = false;

// watch for HDMI plug messages if the hdmi switch exists

if (new File("/sys/class/switch/hdmi_hpd/state").exists()) {

if (SystemProperties.getBoolean("ro.platform.has.mbxuimode", false)){

SystemProperties.set("sys.boot.logo", "android");

if(SystemProperties.getBoolean("ro.hw.cvbs.onboard", true) && !SystemProperties.getBoolean("ro.hdmiplugdetect.dis", false)){

mMboxOutputModeManager.initOutputMode();

mHDMIObserver.startObserving(HDMI_TX_PLUG_UEVENT);

}

} else {

mHDMIObserver.startObserving(HDMI_TX_PLUG_UEVENT);

}

final String filename = "/sys/class/switch/hdmi_hpd/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) {

}

}

}

}

mHdmiHwPlugged = plugged;

if (!SystemProperties.getBoolean("ro.vout.dualdisplay", false)) {

if (getCurDisplayMode().equals("panel") || !plugged || SystemProperties.getBoolean("ro.platform.has.mbxuimode", false)) {

plugged = false;

}

}

if (SystemProperties.getBoolean("ro.vout.dualdisplay", false)) {

setDualDisplay(plugged);

}

if (SystemProperties.getBoolean("ro.vout.dualdisplay2", false)) {

plugged = false;

setDualDisplay(plugged);

}

Intent it = new Intent(WindowManagerPolicy.ACTION_HDMI_PLUGGED);

it.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);

it.putExtra(WindowManagerPolicy.EXTRA_HDMI_PLUGGED_STATE, plugged);

mContext.sendStickyBroadcastAsUser(it, UserHandle.OWNER);

}

此函数中有mHDMIObserver.startObserving(HDMI_TX_PLUG_UEVENT),开始监听了HDMI的状态, UEventObserver代码如下:

private UEventObserver mHDMIObserver = new UEventObserver() {

@Override

public void onUEvent(UEventObserver.UEvent event) {

Log.d(TAG , "mHDMIObserver");

setHdmiHwPlugged("1".equals(event.get("SWITCH_STATE")));

}

};

setHdmiHwPlugged中有段关键代码为:

if(SystemProperties.getBoolean("persist.sys.autosuspend.hdmi", false)) {

if (plugged && !isTvSuspend) {

disableAutoSuspend();

} else {

enableAutoSuspend();

}

}

persist.sys.autosuspend.hdmi属性为HDMI待机开关,然后当判断HDMI线拔出时,就调用enableAutoSuspend进入待机流程,代码如下:

public void enableAutoSuspend() {

disableAutoSuspend();

int def_timeout = 2 * 60 * 1000; //default 2min

if (timeout > 0) {

Slog.d(TAG, "enable auto suspend");

mAutoSuspendTimer = new Timer();

TimerTask task = new TimerTask(){

public void run() {

Slog.d(TAG, "goto auto suspend");

String proj_type = SystemProperties.get("sys.proj.type", "ott");

String tender_type = SystemProperties.get("sys.proj.tender.type", null);

Log.i(TAG, "Auto suspend sys.proj.type: " + proj_type + ", sys.proj.tender.type: " + tender_type);

if ("telecom".equals(proj_type) && "jicai".equals(tender_type)) {

sendKeyEvent(KeyEvent.KEYCODE_HOME);

}

String rx_sense = mSystemWriteManager.readSysfs("/sys/class/switch/hdmi_rxsense/state");

if("0".equals(rx_sense))

mPowerManager.goToSleep(SystemClock.uptimeMillis());

}

};

mAutoSuspendTimer.schedule(task, timeout);

isTvSuspend = false;

}

}

至此,常用HDMI功能开发已介绍完毕。

你可能感兴趣的:(android,hdmi,开发)