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

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

       最开始可以通过查看分析源代码,找到到NfcService的相关代码,如下: packages\apps\Nfc\src\com\android\nfc\NfcService.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 屏幕亮了,并且是解锁状态

代码定义如下,在packages\apps\Nfc\src\com\android\nfc\ScreenStateHelper中定义

    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()) {

====================================================================================

上面代码用Handler做十分钟定时器的时候,时间不准确,改用AlarmManager做定时器,下面是修改的代码

//added by ouyang start [2015-11-4] 40分钟后恢复NFC默认值的广播
            else if (action.equals("com.runbo.camera.nfc.restore")) {
            	//设置在屏幕解锁情况下可以使用NFC
            	Log.d("oyp", "<----com.runbo.camera.nfc.restore---->");
				setNFC_POLLING_MODE(NFC_POLLING_MODE_DEFALUT);
				applyRouting(true);
				Log.d("oyp", "3、NFC_POLLING_MODE="+getNFC_POLLING_MODE());

                SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                Date date=new Date();
                String time=sdf.format(date);
                Log.d("oyp", "time after="+time);
            }
            //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());
					//使用AlarmManager来做定时
					AlarmManager aManager = (AlarmManager)context.getSystemService(Service.ALARM_SERVICE);
					// 指定启动AlarmActivity组件
					Intent nfcRestoreIntent = new Intent("com.runbo.camera.nfc.restore");
					// 创建PendingIntent对象
					PendingIntent pi = PendingIntent.getBroadcast(context, 0, nfcRestoreIntent, 0);
					//设定一个40分钟后的时间
					Calendar calendar=Calendar.getInstance();
					calendar.setTimeInMillis(System.currentTimeMillis());
					calendar.add(Calendar.MINUTE,TIME_TO_Restore_Default_Values);
					//先取消定时器
					//aManager.cancel(pi);
					// 设置AlarmManager将在Calendar对应的时间启动指定组件
					aManager.set(AlarmManager.RTC_WAKEUP,calendar.getTimeInMillis(), pi);	

                    SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    Date date=new Date();
                    String time=sdf.format(date);
                    Log.d("oyp", "time before="+time);

//					//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]

   将Handler的代码注释掉了,改用AlarmManager来做定时器,到达指定的时间后,发送一个“com.runbo.camera.nfc.restore”广播,这个广播也让该广播接收者来接收,因此动态注册广播的代码改成:

      //如果是Hanbang的定制软件
        if (android.os.SystemProperties.isHanbangVersion()) {
            //接收Camera物理键按下后松开,发出的广播
            filter.addAction("com.runbo.camera.key.up");
            //接收NFC恢复默认值的广播
            filter.addAction("com.runbo.camera.nfc.restore");
        }
        //added by ouyang end [2015-10-19] 

因为之前使用秒来计时,现在使用分钟来计时,因此TIME_TO_Restore_Default_Values改成40,即40分钟

 //从黑屏可用NFC恢复到要解锁才能用NFC的时间
static final int TIME_TO_Restore_Default_Values=40; //40分钟

 

====================================================================================

下面呈上修改后的代码和没修改的代码,经验证,完美!

修改之后的代码如下:

修改之前的代码如下:

               ====================================================================================

  作者:欧阳鹏  欢迎转载,与人分享是进步的源泉!

  转载请保留原文地址:http://blog.csdn.net/ouyang_peng

====================================================================================

时间: 2015-10-19

Android系统移植与调试之-------&gt;如何修改Android手机NFC模块,使黑屏时候能够使用NFC的相关文章

Android系统移植与调试之-------&amp;gt;如何修改Android设备添加重启、飞行模式、静音模式等功能(一)

1.首先先来看一下修改前后的效果对比图 修改之后的图片 确认重启界面  具体的修改内容在下一篇中具体介绍. Android系统移植与调试之------->如何修改Android设备添加重启.飞行模式.静音模式等功能(二) ==================================================================================================   作者:欧阳鹏  欢迎转载,与人分享是进步的源泉!   转载请保留原文地址:h

Android系统移植与调试之-------&amp;gt;如何修改Android手机显示的4G信号强度的格子数

           在修改显示的信号强度之前,先了解一下什么是dB,什么是dBm? 1.dB dB是一个表征相对值的值,纯粹的比值,只表示两个量的相对大小关系,没有单位,当考虑甲的功率相比于乙功率大或小多少个dB时, 按下面的计算公式:10log(甲功率/乙功率),如果采用两者的电压比计算,要用20log(甲电压/乙电压).) [例] 甲功率比乙功率大一倍,那么10lg(甲功率/乙功率)=10lg2=3dB.也就是说,甲的功率比乙的功率大3 dB. 反之,如果甲的功率是乙的功率的一半,则甲的功

Android系统移植与调试之-------&amp;gt;如何修改Android启动动画和开机声音

附:本文转载于  http://www.cnblogs.com/jqyp/archive/2012/03/07/2383973.html 1. Linux 系统启动,出现Linux小企鹅画面(reboot)(Android 1.5及以上版本已经取消加载图片): 2. Android平台启动初始化,出现"A N D R I O D"文字字样画面: 3. Android平台图形系统启动,出现含闪动的ANDROID字样的动画图片(start). 现在我们说的是第三种方式(基于模拟器): an

Android系统移植与调试之-------&amp;gt;如何修改Android设备状态条上音量加减键在横竖屏切换的时候的显示于隐藏

这两天由于一个客户的要求,将MID竖屏时候的状态条上的音量键去掉.所以尝试修改了一下,成功了,分享一下经验. 先看一下修改后的效果图,如下所示 . 横屏的时候:有音量加减键 竖屏的时候:音量加减键被去掉了  然后来说一说我的解决思路. 首先我查看了\mx0831-0525\frameworks\base\packages\SystemUI\res\layout\system_bar.xml文件 <?xml version="1.0" encoding="utf-8&qu

Android系统移植与调试之-------&amp;gt;如何修改Android设备存储盘符名称与Android设备的型号

 一.修改Android设备存储盘符名称 (注:TBDG1073为我的项目名称) 1.修改device/other/TBDG1073/system.prop 文件  2.修改ro.media.patition.label属性为OuyangPeng  3.修改完后重新编译  4.将MID通过USB连接到电脑  显示盘符为OuyangPeng 二.修改Android设备的型号   1.进入到~/mx0831-0525/device/other/TBDG1073目录  2.找到TBDG1073.mk文

Android系统移植与调试之-------&amp;gt;如何修改Android自带的apk出现一圈圈类似鸡蛋的花纹

最近被一个问题烦恼到了,就是android4.1系统自带的Email.文件管理器.信息等apk都出现同一个问题,就是现实在平板上的时候会出现一圈圈类似鸡蛋的花纹. 我想了两种方法来解决,第一种方法没有解决,第二种方法解决了问题. 现在我来说说我第一种方法:我尝试去直接修改相关apk的res/drawable目录下的相应图片,因为源码中的图片都不是纯白色的,所以我自己做了图片替换进去.然后重新编译,但是没有其效果. 我的第二种方法起了作用,现在就来看看第二种方法的解决步骤,拿修改Email apk

Android系统移植与调试之-------&amp;gt;如何修改Android系统默认显示【开发者选项】并默认打开【USB调试】和【未知来源】开关

              今天有个用户对[设置]有个特殊的要求,即: 1.开机的时候默认显示[开发者选项]并打开[USB调试]开关    ([Developer options]-->[USB debugging]) 2.开机的时候默认打开[安全]-->[未知来源]的开关    ([Security]--->[Unknown sources])     1.首先解决[设置]界面默认显示[开发者选项]的问题 查看源代码:packages/apps/Settings/src/com/and

Android系统移植与调试之-------&amp;gt;如何修改Android默认字体大小和设置里面字体大小比例

           因为我修改 ro.sf.lcd_density的值,将它从160修改 为120,所以导致整个系统的字体都变得很小.因此需要将整个字体变大,并且在设置-->显示-->字体大小的4个选项的值都必须变大.我想到的思路是将字体的缩放比例调大一些,下面是我的修改步骤. 1.修改默认字体的大小 Step1: 修改frameworks/base/core/java/android/content/res/Configuration.java   文件中的setToDefaults()方

Android系统移植与调试之-------&amp;gt;如何修改Android设备的默认休眠时间

1.找到~/mx0831-0525/frameworks/base/packages/SettingsProvider/res/values/ defaults.xml文件 2.修改默认休眠时间 3.重新编译 4.上述方法编译之后发现没有其效果,原来被device/other/TBDG1073/overlay/frameworks/base/packages/SettingsProvider/res/values/defaults.xml文件中的值所覆盖了,如果device下面有相应的文件会优先