简体   繁体   中英

How do I test/simulate NFC foreground dispatching?

I know you can simulate NFC tags simply by creating an intent and starting and activity with it. From my understanding and testing this only works, if you add intent-filters to your manifest.

I want to simulate tags and dispatch them to an activity/fragment via foreground dispatch only, so starting the activity with intent-filters in the manifest is not an option for me.

The structure of my program looks like this: Activity -> several Fragments, one of them is interested in NFC tags via foreground dispatching. The nfc-fragment has the necessary code for pendingIntent and dispatch-enabling and -disabling. The activity implements the onNewIntent() method, which invokes further handling of the intent via a method in the nfc-fragment, if the nfc-fragment is active.

The program works fine, but I need to test the behaviour with automated tests.

I've already tried using

final Intent intent = new Intent(NfcAdapter.ACTION_TAG_DISCOVERED);
intent.putExtra(NfcAdapter.EXTRA_ID, "1234567890".getBytes());
solo.getCurrentActivity().startActivity(intent);

but this just gives me an ActivityNotFoundException . Currently I retrieve the nfc-fragment and call the method to handle the intent manually from inside the test, but this gives me

android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

since the method involves updating Views and whatnot. It works somehow , since I just need to switch to a different activity or fragment and then go back to get the view updates, but I'd like to know if there is a better and cleaner way of doing this.

I appreciate your help, let me know if you need more information.

I assume that solo.getCurrentActivity() refers to the activity that should receive the NFC intent, otherwise you have to adapt the activity class and context to refer to the right values:

Class activityCls = solo.getCurrentActivity().getClass();
Context packageContext = solo.getCurrentActivity();

Then you create the pending intent (better yet, you could use the PendingIntent that was passed to the enableForegroundDispatch() method):

PendingIntent pendingIntent = PendingIntent.getActivity(
    packageContext,
    0,
    new Intent(packageContext, activityCls).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP),
    0);

Set up the parameters of the NFC intent:

String intentAction = NfcAdapter.ACTION_TAG_DISCOVERED;
Tag tag = ...;
byte[] tagId = ...;
NdefMessage ndefMessage = ...;

Prepare the NFC intent:

Intent intent = new Intent();
intent.setAction(intentAction);
intent.putExtra(NfcAdapter.EXTRA_TAG, tag);
intent.putExtra(NfcAdapter.EXTRA_ID, tagId);
if (ndefMessage != null) {
    intent.putExtra(NfcAdapter.EXTRA_NDEF_MESSAGES, new NdefMessage[] { ndefMessage });

    if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intentAction)) {
        Uri uri = message.getRecords()[0].toUri();
        String mime = message.getRecords()[0].toMimeType();
        if (uri != null) {
            intent.setData(uri);
        } else {
            intent.setType(mime);
        }
    }
}

Send the pending intent using the parametrization set-up above:

pendingIntent.send(packageContext, Activity.RESULT_OK, intent);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM