Android system transplantation and debugging -------) how to modify the NFC module of the Android mobile phone so that NFC can be used in the black screen
We all know that, without modifying the source code, NFC can only be used after unlocking. However, NFC cannot be used in two statuses: screen lock and black screen. However, a customer recently asked the mobile phone to be able to use NFC in the black screen status, therefore, we need to modify the Android source code about the NFC module.
You can check the source code of the analysis and find the relevant code of NfcService, as shown in the following code: packagesappsNfcsrccomandroid fcNfcService. java
Find row 186, which defines the minimum screen status that NFC can use
// minimum screen state that enables NFC polling static final int NFC_POLLING_MODE = ScreenStateHelper.SCREEN_STATE_ON_UNLOCKED;
These statuses are:
SCREEN_STATE_OFF black screen status
SCREEN_STATE_ON_LOCKED: the screen is on, but the screen is locked.
SCREEN_STATE_ON_UNLOCKED: the screen is on and unlocked.
The code is defined as follows, which is defined in 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;
The above minimum state is called in the computeDiscoveryParameters (int screenState) method of NfcService. java in the row 1706th. The method code is as follows:
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) {// called here // 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 ();}
Therefore, if you want to change to a black screen, you only need to change the variable NFC_POLLING_MODE to NFC.
ScreenStateHelper. SCREEN_STATE_OFF. The Code is as follows:
// 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;
But in this case, the phone will not sleep, observe the current and voltage of the battery, and find that the phone is always beating. In this way, the phone will not sleep in the black screen state, which will consume a lot of power, so it needs to be optimized.
The customer's requirement is: When you double-click the physical button Camera, you can use NFC for 10 minutes or 10 minutes on the black screen. NFC is almost finished, and then the status is changed back, that is, NFC can only be used in the unlocked State. In this way, NFC can be used for black screens and power-saving.
Therefore, the idea is as follows:
1. Receive the broadcast sent by the physical key Camera to check whether it is a double-click. Change the minimum mode of NFC_POLLING_MODE to ScreenStateHelper. SCREEN_STATE_OFF.
2. You need to write a timer to change the minimum mode of NFC_POLLING_MODE to the original ScreenStateHelper. SCREEN_STATE_ON_UNLOCKED after 10 minutes.
Therefore, first define several constants, starting from the static final int NFC_POLLING_MODE = ScreenStateHelper. SCREEN_STATE_ON_UNLOCKED; of row 185th. The modification code is as follows:
// 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; // The default value is NFCstatic final int NFC_POLLING_MODE_DEFALUT = ScreenStateHelper. SCREEN_STATE_ON_UNLOCKED; // NFC static final int NFC_POLLING_MODE_SCREEN_OFF = ScreenStateHelper can also be used in case of a black screen. SCREEN_STATE_OFF; // The Screen status when NFC is enabled by default. static int NFC_POLLING_MODE = ScreenStateHelper. optional; public static int getNFC_POLLING_MODE () {return NFC_POLLING_MODE;} public static void setNFC_POLLING_MODE (int success) {NFC_POLLING_MODE = success;} // whether to double-click the Camera key static boolean isDoublePress = false; // restore from the available NFC on the black screen to the time when NFC can be used to unlock static final int TIME_TO_Restore_Default_Values = (60*1000) * 10; // 10 minutes 10*1000*60 // edited by ouyang [] end
Step 2: Write a broadcast receiver to process the broadcast triggered when the physical button Camera is pressed and released.
To determine double-click Camera, you only need to receive the broadcast sent when the Camera key is released. This broadcast is defined by the company and is defined as com. runbo. camera. key. up. So now we are processing this broadcast. Because a broadcast receiver is dynamically registered in the code, we can register another Intent in this broadcast receiver type. The Code is as follows:
// 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] // press the Camera physical key and release the broadcast filter. addAction (com. runbo. camera. key. up); // added by ouyang end [2015-10-19] registerForAirplaneMode (filter); mContext. registerReceiverAsUser (mReceiver, UserHandle. ALL, filter, null, null );
In this way, we can process this double-click Camera key in mReceiver. In the onReceive method in mReceiver, we can determine whether the action is com. runbo. camera. key. up. The code for line 2295 is as follows:
// Added by ouyang start [] After the Camera physical key is pressed, release 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 (); // click if (! IsDoublePress) {isDoublePress = true; // if you click the Camera key again such as MS, you can double-click it and directly enter the else statement block // ms to trigger this thread, check whether to click or double-click Runnable CheckDoubleRunnable = new Runnable () {@ Override public void run () {if (isDoublePress) {Log. I (oyp, <---- Single Press the Camera Key ---->); // displayed as click} else {Log. I (oyp, <---- Double Press the Camera Key ---->); // displayed as Double-click} isDoublePress = false; // click the Camera Key after Ms, or enter the if statement block }}; checkHandler. postDelayed (CheckDoubleRunnable, 500); // two clicks within ms, trigger double-click} // two clicks within ms, trigger double-click else {isDoublePress = false; // double-click, set this value to false. The next time you click the Camera key, you can still click it or enter the if statement block. // you can still use NFCsetNFC_POLLING_MODE (NFC_POLLING_MODE_SCREEN_OFF) when the screen is off ); applyRouting (true); Log. d (oyp, 2, NFC_POLLING_MODE = + getNFC_POLLING_MODE (); // trigger the thread after 10 minutes and restore the original value Runnable restoredefavalues = new Runnable () {@ Override public void run () {// when unlocking the screen, you can use NFCsetNFC_POLLING_MODE (NFC_POLLING_MODE_DEFALUT); applyRouting (true); Log. d (oyp, 3, NFC_POLLING_MODE = + getNFC_POLLING_MODE () ;}}; restoreHandler. removeCallbacks (restoredefavaluvalues); // cancel the timer restoreHandler first. postDelayed (RestoreDefaultValues, TIME_TO_Restore_Default_Values); // restore the original value 10 minutes later} // added by ouyang end []
The judgment statement in the computeDiscoveryParameters () method is also removed. The 1733 line of code is as follows:
// if (screenState >= NFC_POLLING_MODE) { //edited by ouyang [2015-10-19 11:13:17] if (screenState >= getNFC_POLLING_MODE()) {