Nexus SをAndroid 4.0.3にUpdateしました。
波形をとりながら動作確認中を行ったところ、面白い発見をしたので記事にしました。
キーガードロック画面のNFC動作
まずはAndroid2.3.6 GingerBread版Nexus Sの波形です。
電源キーによりスクリーンOFF → ONを行いキーガードロック画面を表示しました。
スクリーンON中はNFC電源ONになり、その波形が現れています。
約5秒後、再びスクリーンOFFになりました。
次はAndroid4.0.3 Ice Cream Sandwich版Nexus Sの波形です。
同じ操作でキーガードロック画面を表示しました。
しかし、スクリーンONになってもNFC電源ONの波形が現れません!
どうやら、ICSの変更でキーガードロック中はNFC電源が入らないように修正されているようです。
プログラムを確認してみましょう。
まずは、Android2.3.6 GingerBreadのプログラムです。
スクリーンON/OFFの動作処理を行っているのは以下のファイルです。
\packages\apps\Nfc\src\com\android\nfc
- NfcService.java
以下の処理により、電源ONになりNFCタグ受信待ち状態となります。
つぎは、Android4.0.3 Ice Cream Sandwichのプログラム確認。
\packages\apps\Nfc\src\com\android\nfc
- NfcService.java
以下のように処理が変更され、スクリーンONでは電源ONとなりません。
電源ONとなるタイミングはIntent.ACTION_USER_PRESENTを受信した時、
つまり、キーガードが解除された時に電源ONとなります。
波形をとりながら動作確認中を行ったところ、面白い発見をしたので記事にしました。
キーガードロック画面のNFC動作
まずはAndroid2.3.6 GingerBread版Nexus Sの波形です。
電源キーによりスクリーンOFF → ONを行いキーガードロック画面を表示しました。
スクリーンON中はNFC電源ONになり、その波形が現れています。
約5秒後、再びスクリーンOFFになりました。
次はAndroid4.0.3 Ice Cream Sandwich版Nexus Sの波形です。
同じ操作でキーガードロック画面を表示しました。
しかし、スクリーンONになってもNFC電源ONの波形が現れません!
どうやら、ICSの変更でキーガードロック中はNFC電源が入らないように修正されているようです。
プログラムを確認してみましょう。
まずは、Android2.3.6 GingerBreadのプログラムです。
スクリーンON/OFFの動作処理を行っているのは以下のファイルです。
\packages\apps\Nfc\src\com\android\nfc
- NfcService.java
private class EnableDisableDiscoveryTask extends AsyncTask{
@Override
protected Void doInBackground(Boolean... enable) {
if (enable != null && enable.length > 0 && enable[0]) {
synchronized (NfcService.this) {
mScreenOn = true;
applyRouting();
}
} else {
:
}
return null;
}
}
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
:
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
:
new EnableDisableDiscoveryTask().execute(new Boolean(true));
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
:
}
}
以下の処理により、電源ONになりNFCタグ受信待ち状態となります。
- スクリーンONのIntentであるIntent.ACTION_SCREEN_ONを受信する
- EnableDisableDiscoveryTask().execute()をコール
- applyRouting()をコール
- mManager.enableDiscovery(DISCOVERY_MODE_READER)をコール
つぎは、Android4.0.3 Ice Cream Sandwichのプログラム確認。
\packages\apps\Nfc\src\com\android\nfc
- NfcService.java
/**
* Read mScreenState and apply NFC-C polling and NFC-EE routing
*/
void applyRouting(boolean force) {
synchronized (this) {
:
// configure NFC-C polling
if (mScreenState >= POLLING_MODE) {
if (force || !mNfcPollingEnabled) {
Log.d(TAG, "NFC-C ON");
mNfcPollingEnabled = true;
mDeviceHost.enableDiscovery();
}
} else {
if (force || mNfcPollingEnabled) {
Log.d(TAG, "NFC-C OFF");
mNfcPollingEnabled = false;
mDeviceHost.disableDiscovery();
}
}
}
}
class ApplyRoutingTask extends AsyncTask{
@Override
protected Void doInBackground(Integer... params) {
synchronized (NfcService.this) {
if (params == null || params.length != 1) {
// force apply current routing
applyRouting(true);
return null;
}
mScreenState = params[0].intValue();
boolean needWakelock = mScreenState == SCREEN_STATE_OFF;
if (needWakelock) {
mWakeLock.acquire();
}
applyRouting(false);
if (needWakelock) {
mWakeLock.release();
}
return null;
}
}
}
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
:
} else if (action.equals(Intent.ACTION_SCREEN_ON)
|| action.equals(Intent.ACTION_SCREEN_OFF)
|| action.equals(Intent.ACTION_USER_PRESENT)) {
// Perform applyRouting() in AsyncTask to serialize blocking calls
int screenState = SCREEN_STATE_OFF;
if (action.equals(Intent.ACTION_SCREEN_OFF)) {
screenState = SCREEN_STATE_OFF;
} else if (action.equals(Intent.ACTION_SCREEN_ON)) {
screenState = mKeyguard.isKeyguardLocked() ?
SCREEN_STATE_ON_LOCKED : SCREEN_STATE_ON_UNLOCKED;
} else if (action.equals(Intent.ACTION_USER_PRESENT)) {
screenState = SCREEN_STATE_ON_UNLOCKED;
}
new ApplyRoutingTask().execute(Integer.valueOf(screenState));
} else if (action.equals(ACTION_MASTER_CLEAR_NOTIFICATION)) {
:
}
}
以下のように処理が変更され、スクリーンONでは電源ONとなりません。
- スクリーンONのIntentであるIntent.ACTION_SCREEN_ONを受信する
- mKeyguard.isKeyguardLocked()でキーガード状態かどうか確認する
- キーガード状態の場合、SCREEN_STATE_ON_LOCKEDを引数としてApplyRoutingTask().execute()をコール
- applyRouting(false)をコール
- mScreenStateがSCREEN_STATE_ON_LOCKEDなので、mDeviceHost.enableDiscovery()はコールしない
電源ONとなるタイミングはIntent.ACTION_USER_PRESENTを受信した時、
つまり、キーガードが解除された時に電源ONとなります。