2012年1月31日火曜日

キーガード中のNFC動作 GingerBread と Ice Cream Sandwichの違い

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

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タグ受信待ち状態となります。
  1. スクリーンONのIntentであるIntent.ACTION_SCREEN_ONを受信する
  2. EnableDisableDiscoveryTask().execute()をコール
  3. applyRouting()をコール
  4. 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となりません。
  1. スクリーンONのIntentであるIntent.ACTION_SCREEN_ONを受信する
  2. mKeyguard.isKeyguardLocked()でキーガード状態かどうか確認する
  3. キーガード状態の場合、SCREEN_STATE_ON_LOCKEDを引数としてApplyRoutingTask().execute()をコール
  4. applyRouting(false)をコール
  5. mScreenStateがSCREEN_STATE_ON_LOCKEDなので、mDeviceHost.enableDiscovery()はコールしない

電源ONとなるタイミングはIntent.ACTION_USER_PRESENTを受信した時、
つまり、キーガードが解除された時に電源ONとなります。
140 180 Android , 省電力 , 電力測定

記載されている会社名、および商品名等は、各社の商標または登録商標です。

0 コメント:

コメントを投稿

Related Posts Plugin for WordPress, Blogger...