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

 

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

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

 

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

 

?
1
2
// 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中定义

 

?
1
2
3
4
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)方法中被调用,用来判断的,方法代码如下:

 

 

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
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即可,代码如下:

 

 

 

?
1
2
3
// 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;处开始修改,修改代码如下:

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 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行

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
// 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行代码如下:

 

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
//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行代码如下:

 

 

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

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值