Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android系統移植與調試之-------)如何修改Android手機NFC模塊,使黑屏時候能夠使用NFC

Android系統移植與調試之-------)如何修改Android手機NFC模塊,使黑屏時候能夠使用NFC

編輯:關於Android編程

我們都知道在不修改源代碼的情況下,只能是解鎖之後才能使用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()) {

 

 

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved