Android系统移植与调试之-------)如何修改Android手机NFC模块,使黑屏时候能够使用NFC

来源:互联网 时间:1970-01-01


我们都知道在不修改源代码的情况下,只能是解锁之后才能使用NFC功能。而在锁屏和黑屏2个状态下是没办法用NFC的,但是最近有个客户要求手机在黑屏状态下能够使用NFC,因此我们需要去修改Android源代码关于NFC模块。

最开始可以通过查看分析源代码,找到到NfcService的相关代码,如下: packagesappsNfcsrccomandroid fcNfcService.java

 

找到186行,这句是定义NFC能够使用的屏幕最小状态

 

// minimum screen state that enables NFC polling static final int NFC_POLLING_MODE = ScreenStateHelper.SCREEN_STATE_ON_UNLOCKED;

 

 

这几个状态分别是:

SCREEN_STATE_OFF黑屏状态

SCREEN_STATE_ON_LOCKED屏幕亮了,但是是锁屏状态

SCREEN_STATE_ON_UNLOCKED 屏幕亮了,并且是解锁状态

代码定义如下,在packagesappsNfcsrccomandroid fcScreenStateHelper中定义

 

 static final int SCREEN_STATE_UNKNOWN = 0; static final int SCREEN_STATE_OFF = 1; static final int SCREEN_STATE_ON_LOCKED = 2; static final int SCREEN_STATE_ON_UNLOCKED = 3;

上面的这个最小状态在NfcService.java的第1706行,computeDiscoveryParameters(int screenState)方法中被调用,用来判断的,方法代码如下:

 

 

 

private NfcDiscoveryParameters computeDiscoveryParameters(int screenState) { Log.d(TAG, computeDiscoveryParameters() screenState:+describeScreenState(screenState)); if(screenState == ScreenStateHelper.SCREEN_STATE_ON_LOCKED) Log.d(TAG, !!!! SCREEN_STATE_ON_LOCKED,, mNfcUnlockManager.isLockscreenPollingEnabled():+mNfcUnlockManager.isLockscreenPollingEnabled()); // Recompute discovery parameters based on screen state NfcDiscoveryParameters.Builder paramsBuilder = NfcDiscoveryParameters.newBuilder(); // Polling if (screenState >= NFC_POLLING_MODE) {//这里被调用 // Check if reader-mode is enabled if (mReaderModeParams != null) { int techMask = 0; if ((mReaderModeParams.flags & NfcAdapter.FLAG_READER_NFC_A) != 0) techMask |= NFC_POLL_A; if ((mReaderModeParams.flags & NfcAdapter.FLAG_READER_NFC_B) != 0) techMask |= NFC_POLL_B; if ((mReaderModeParams.flags & NfcAdapter.FLAG_READER_NFC_F) != 0) techMask |= NFC_POLL_F; if ((mReaderModeParams.flags & NfcAdapter.FLAG_READER_NFC_V) != 0) techMask |= NFC_POLL_ISO15693; if ((mReaderModeParams.flags & NfcAdapter.FLAG_READER_NFC_BARCODE) != 0) techMask |= NFC_POLL_KOVIO; Log.d(TAG, mReaderModeParams != null paramsBuilder.setTechMask:+techMask); paramsBuilder.setTechMask(techMask); paramsBuilder.setEnableReaderMode(true); } else { Log.d(TAG, mReaderModeParams == null paramsBuilder.setTechMask:+NfcDiscoveryParameters.NFC_POLL_DEFAULT + NFC_POLL_DEFAULT); paramsBuilder.setTechMask(NfcDiscoveryParameters.NFC_POLL_DEFAULT); paramsBuilder.setEnableP2p(mIsNdefPushEnabled); } } else if (screenState == ScreenStateHelper.SCREEN_STATE_ON_LOCKED && mInProvisionMode) { paramsBuilder.setTechMask(NfcDiscoveryParameters.NFC_POLL_DEFAULT); // enable P2P for MFM/EDU/Corp provisioning paramsBuilder.setEnableP2p(true); } else if (screenState == ScreenStateHelper.SCREEN_STATE_ON_LOCKED && mNfcUnlockManager.isLockscreenPollingEnabled()) { Log.d(TAG, !!!! SCREEN_STATE_ON_LOCKED setTechMask ); // For lock-screen tags, no low-power polling paramsBuilder.setTechMask(mNfcUnlockManager.getLockscreenPollMask()); paramsBuilder.setEnableLowPowerDiscovery(false); paramsBuilder.setEnableP2p(false); } if (mIsHceCapable && mScreenState >= ScreenStateHelper.SCREEN_STATE_ON_LOCKED) { // Host routing is always enabled at lock screen or later Log.d(TAG, >= SCREEN_STATE_ON_LOCKED paramsBuilder.setEnableHostRouting(true) ); paramsBuilder.setEnableHostRouting(true); } return paramsBuilder.build(); }
因此如果要改成黑屏状态下可以使用NFC的话,只要将变量NFC_POLLING_MODE改成
ScreenStateHelper.SCREEN_STATE_OFF即可,代码如下:

 

 

 

 // minimum screen state that enables NFC polling //static final int NFC_POLLING_MODE = ScreenStateHelper.SCREEN_STATE_ON_UNLOCKED; static final int NFC_POLLING_MODE = ScreenStateHelper.SCREEN_STATE_OFF;

但是这样的话,手机会一直不休眠,观察电池的电流和电压发现,一直在跳动,这样在黑屏状态下,手机不会休眠,会很耗电,因此还要优化。

 

 

客户的要求是:当双击物理按键Camera键的时候,可以在黑屏状态下使用NFC十分钟,十分钟之类,差不多关于NFC的工作完成了,之后将状态改回来,即:只能在解锁状态下使用NFC,这样的话就可以黑屏使用NFC又节电。

因此,思路如下:

1、接收物理按键Camera键发送的广播,来判断是双击,并将NFC_POLLING_MODE的最小模式改为ScreenStateHelper.SCREEN_STATE_OFF。

2、需要写一个定时器来处理十分钟之后将NFC_POLLING_MODE的最小模式改为会原来的ScreenStateHelper.SCREEN_STATE_ON_UNLOCKED。

 

因此,首先先定义几个常量,从第185行static final int NFC_POLLING_MODE= ScreenStateHelper.SCREEN_STATE_ON_UNLOCKED;处开始修改,修改代码如下:

 

 // minimum screen state that enables NFC polling // edited by ouyang [2015-10-19] start// static final int NFC_POLLING_MODE= ScreenStateHelper.SCREEN_STATE_ON_UNLOCKED; //默认为要解锁才能使用NFC static final int NFC_POLLING_MODE_DEFALUT = ScreenStateHelper.SCREEN_STATE_ON_UNLOCKED; //在黑屏情况下也可以使用NFC static final int NFC_POLLING_MODE_SCREEN_OFF = ScreenStateHelper.SCREEN_STATE_OFF; //默认能使用NFC时的屏幕状态 static int NFC_POLLING_MODE = ScreenStateHelper.SCREEN_STATE_ON_UNLOCKED; public static int getNFC_POLLING_MODE() { return NFC_POLLING_MODE; } public static void setNFC_POLLING_MODE(int mNFC_POLLING_MODE) { NFC_POLLING_MODE = mNFC_POLLING_MODE; } //是否是双击Camera键 static boolean isDoublePress=false; //从黑屏可用NFC恢复到要解锁才能用NFC的时间 static final int TIME_TO_Restore_Default_Values=(60*1000)*10;//10分钟 10*1000*60 // edited by ouyang [2015-10-19] end

第二步:写一个广播接收者来处理物理按键Camera,按下和松开时发出的广播。

 

因为是要判断双击Camera,所以这里只要接收松开Camera键时发出的广播即可。这个广播是公司自己定义的,定义的广播为:com.runbo.camera.key.up。所以现在处理这个广播。因为代码中本来就动态注册了一个广播接收者,因此我们在这个广播接收者种再注册一个Intent即可。代码如下:在第450行

 

// Intents for all users IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF); filter.addAction(Intent.ACTION_SCREEN_ON); filter.addAction(Intent.ACTION_USER_PRESENT); filter.addAction(Intent.ACTION_USER_SWITCHED); //added by ouyang start [2015-10-19] //Camera物理键按下后松开 发出的广播 filter.addAction(com.runbo.camera.key.up); //added by ouyang end [2015-10-19] registerForAirplaneMode(filter); mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, null);

这样我们处理这个双击Camera键可以在mReceiver中处理了,在mReceiver中的onReceive方法中,判断action是否是com.runbo.camera.key.up,2295行代码如下:

 

 

 //added by ouyang start [2015-10-19] Camera物理键按下后松开 else if (action.equals(com.runbo.camera.key.up)) { Log.d(oyp, <----com.runbo.camera.key.up---->); Handler checkHandler=new Handler(); Handler restoreHandler=new Handler(); //单击 if (!isDoublePress) { isDoublePress=true;//500ms之类再单击Camera键的话,就是双击了,直接进入 else语句块 //500ms后触发该线程,查看是单击还是双击 Runnable CheckDoubleRunnable=new Runnable(){ @Override public void run() { if (isDoublePress) { Log.i(oyp, <----Single Press the Camera Key---->); //显示为单击 }else{ Log.i(oyp, <----Double Press the Camera Key---->); //显示为双击 } isDoublePress=false;//500ms后在单击Camera键的话 依旧是单击 ,还是进入了 if语句块 } }; checkHandler.postDelayed(CheckDoubleRunnable, 500);// 500ms内两次单击,触发双击 } // 500ms内两次单击,触发双击 else{ isDoublePress=false;//双击后,将该值设为false,下次在单击Camera键的话 依旧是单击 ,还是进入了 if语句块 //设置在屏幕关闭情况下仍然可以使用NFC setNFC_POLLING_MODE(NFC_POLLING_MODE_SCREEN_OFF); applyRouting(true); Log.d(oyp, 2、NFC_POLLING_MODE=+getNFC_POLLING_MODE()); //10分钟后触发该线程,恢复原来值 Runnable RestoreDefaultValues=new Runnable(){ @Override public void run() { //设置在屏幕解锁情况下可以使用NFC setNFC_POLLING_MODE(NFC_POLLING_MODE_DEFALUT); applyRouting(true); Log.d(oyp, 3、NFC_POLLING_MODE=+getNFC_POLLING_MODE()); } }; restoreHandler.removeCallbacks(RestoreDefaultValues);//先取消定时器 restoreHandler.postDelayed(RestoreDefaultValues, TIME_TO_Restore_Default_Values);//10分钟后恢复原来值 } } //added by ouyang end [2015-10-19]

还要将computeDiscoveryParameters()方法中的判断语句改掉,1733行代码如下:

 

 

// if (screenState >= NFC_POLLING_MODE) { //edited by ouyang [2015-10-19 11:13:17] if (screenState >= getNFC_POLLING_MODE()) {

 

 

 



相关阅读:
Top