Обмен строками через NFC (Android Beam) между двумя устройствами Android

Я пытаюсь реализовать Android-приложение для связи nfc-p2p.

Я хотел бы одновременно обмениваться строками между двумя устройствами.

Начиная с этого поста ">#25963691 Я обнаружил, что проще всего использовать метод android.nfc.NfcAdapter.invokeBeam() для повторного вызова Android Beam после первой трансляции, чтобы принимающий пользователь мог просто коснуться дисплея и запустить вторую трансляция (без перемещения и повторного размещения устройств).

Я попытался применить это к примеру приложения из онлайн-учебника.

Мое приложение на данный момент не работает: после первой передачи строки Android Beam снова не запускается, даже если в режиме отладки я могу проверить, что вызывается метод invokeBeam.

Кто-нибудь может мне помочь?

Это мои разрешения манифеста:

<uses-permission android:name="android.permission.NFC" />
<uses-feature android:name="android.hardware.nfc" android:required="true"/>

И это моя активность:

public class MainActivity extends Activity implements NfcAdapter.OnNdefPushCompleteCallback, NfcAdapter.CreateNdefMessageCallback {

//The array lists to hold our messages
private ArrayList<String> messagesToSendArray = new ArrayList<>();
private ArrayList<String> messagesReceivedArray = new ArrayList<>();

//Text boxes to add and display our messages
private EditText txtBoxAddMessage;
private TextView txtReceivedMessages;
private TextView txtMessagesToSend;

private NfcAdapter mNfcAdapter;

private  Boolean checkSent;
private  Boolean checkReceived;

public void addMessage(View view) {
    String newMessage = txtBoxAddMessage.getText().toString();
    messagesToSendArray.add(newMessage);
    txtBoxAddMessage.setText(null);
    updateTextViews();

    Toast.makeText(this, "Added Message", Toast.LENGTH_LONG).show();
}

@Override
public void onNdefPushComplete(NfcEvent event) {
    messagesToSendArray.clear();
    //This is called when the system detects that our NdefMessage was
    //Successfully sent

    checkSent = true;
}

public NdefRecord[] createRecords() {
    NdefRecord[] records = new NdefRecord[messagesToSendArray.size() + 1];
    //To Create Messages Manually if API is less than
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
        for (int i = 0; i < messagesToSendArray.size(); i++){
            byte[] payload = messagesToSendArray.get(i).
                    getBytes(Charset.forName("UTF-8"));
            NdefRecord record = new NdefRecord(
                    NdefRecord.TNF_WELL_KNOWN,      //Our 3-bit Type name format
                    NdefRecord.RTD_TEXT,            //Description of our payload
                    new byte[0],                    //The optional id for our Record
                    payload);                       //Our payload for the Record

            records[i] = record;
        }
    }
    //Api is high enough that we can use createMime, which is preferred.
    else {
        for (int i = 0; i < messagesToSendArray.size(); i++){
            byte[] payload = messagesToSendArray.get(i).
                    getBytes(Charset.forName("UTF-8"));

            NdefRecord record = NdefRecord.createMime("text/plain",payload);
            records[i] = record;
        }
    }
    records[messagesToSendArray.size()] = NdefRecord.createApplicationRecord(getPackageName());
    return records;
}


@Override
public NdefMessage createNdefMessage(NfcEvent event) {
    //This will be called when another NFC capable device is detected.
    if (messagesToSendArray.size() == 0) {
        return null;
    }
    //We'll write the createRecords() method in just a moment
    NdefRecord[] recordsToAttach = createRecords();
    //When creating an NdefMessage we need to provide an NdefRecord[]
    return new NdefMessage(recordsToAttach);
}

private void handleNfcIntent(Intent NfcIntent) {
    if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(NfcIntent.getAction())) {
        Parcelable[] receivedArray =
                NfcIntent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);

        if(receivedArray != null) {
            messagesReceivedArray.clear();
            NdefMessage receivedMessage = (NdefMessage) receivedArray[0];
            NdefRecord[] attachedRecords = receivedMessage.getRecords();

            for (NdefRecord record:attachedRecords) {
                String string = new String(record.getPayload());
                //Make sure we don't pass along our AAR (Android Applicatoin Record)
                if (string.equals(getPackageName())) { continue; }
                messagesReceivedArray.add(string);
            }
            Toast.makeText(this, "Received " + messagesReceivedArray.size() +
                    " Messages", Toast.LENGTH_LONG).show();
            updateTextViews();
        }
        else {
            Toast.makeText(this, "Received Blank Parcel", Toast.LENGTH_LONG).show();
        }
    }
}


@Override
public void onNewIntent(Intent intent) {
        handleNfcIntent(intent);
}

@Override
public void onResume() {
    super.onResume();
    updateTextViews();

    if(checkReceived){
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            mNfcAdapter.invokeBeam(MainActivity.this);
            //Toast.makeText(this, "invocato", Toast.LENGTH_SHORT).show();
            Log.e("DEBUG ---", "invocato");
        }
    }
    handleNfcIntent(getIntent());

}

private  void updateTextViews() {
    txtMessagesToSend.setText("Messages To Send:\n");
    //Populate Our list of messages we want to send
    if(messagesToSendArray.size() > 0) {
        for (int i = 0; i < messagesToSendArray.size(); i++) {
            txtMessagesToSend.append(messagesToSendArray.get(i));
            txtMessagesToSend.append("\n");
        }
    }

    txtReceivedMessages.setText("Messages Received:\n");
    //Populate our list of messages we have received
    if (messagesReceivedArray.size() > 0) {
        for (int i = 0; i < messagesReceivedArray.size(); i++) {
            txtReceivedMessages.append(messagesReceivedArray.get(i));
            txtReceivedMessages.append("\n");
        }
        checkReceived = true;
    }
}

//Save our Array Lists of Messages for if the user navigates away
@Override
public void onSaveInstanceState(@NonNull Bundle savedInstanceState) {
    super.onSaveInstanceState(savedInstanceState);
    savedInstanceState.putStringArrayList("messagesToSend", messagesToSendArray);
    savedInstanceState.putStringArrayList("lastMessagesReceived",messagesReceivedArray);
}

//Load our Array Lists of Messages for when the user navigates back
@Override
public void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);
    messagesToSendArray = savedInstanceState.getStringArrayList("messagesToSend");
    messagesReceivedArray = savedInstanceState.getStringArrayList("lastMessagesReceived");
}

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    checkSent = false;
    checkReceived = false;

    //Check if NFC is available on device
    mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
    if(mNfcAdapter != null) {
        //This will refer back to createNdefMessage for what it will send
        mNfcAdapter.setNdefPushMessageCallback(this, this);

        //This will be called if the message is sent successfully
        mNfcAdapter.setOnNdefPushCompleteCallback(this, this);
    }
    else {
        Toast.makeText(this, "NFC not available on this device",
                Toast.LENGTH_SHORT).show();
    }


    txtBoxAddMessage = (EditText) findViewById(R.id.txtBoxAddMessage);
    txtMessagesToSend = (TextView) findViewById(R.id.txtMessageToSend);
    txtReceivedMessages = (TextView) findViewById(R.id.txtMessagesReceived);
    Button btnAddMessage = (Button) findViewById(R.id.buttonAddMessage);

    btnAddMessage.setText("Add Message");
    updateTextViews();

    if (getIntent().getAction().equals(NfcAdapter.ACTION_NDEF_DISCOVERED)) {
        handleNfcIntent(getIntent());
    }
}

}


person Anchor    schedule 06.07.2017    source источник
comment
Привет, ребята, я добился небольшого прогресса в синхронизации вызова нужного события жизненного цикла активности с помощью простого логического флага (обычно мне не нравятся эти трюки). Теперь моя проблема заключается в том, что мне удалось вызвать invokeBeam, но на дисплее устройства ничего не появилось. Я проверяю событие вызова с помощью журнала и всплывающего сообщения сразу после вызова invokeBeam, я вижу сообщение журнала в Logcat, я вижу всплывающее сообщение на дисплее, но не интерфейс Android Beam. Что я ошибаюсь?   -  person Anchor    schedule 27.07.2017
comment
@Override public void onResume() { super.onResume(); возобновлено = правда; обработатьNfcIntent(getIntent()); callInvokeBeam(); }   -  person Anchor    schedule 27.07.2017
comment
private void callInvokeBeam () { if (возобновлено) { if (Build.VERSION.SDK_INT ›= Build.VERSION_CODES.LOLLIPOP) { mNfcAdapter.invokeBeam (MainActivity.this); Toast.makeText(this, Invoked, Toast.LENGTH_LONG).show(); Log.e(DEBUG ---, Invoked); } } }   -  person Anchor    schedule 27.07.2017
comment
@Override public void onPause(){ super.onPause(); возобновлено = ложь; }   -  person Anchor    schedule 27.07.2017