| Index: device/nfc/android/java/src/org/chromium/device/nfc/NfcImpl.java
|
| diff --git a/device/nfc/android/java/src/org/chromium/device/nfc/NfcImpl.java b/device/nfc/android/java/src/org/chromium/device/nfc/NfcImpl.java
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..8ca718d50b2849e968f69f146ca71648c9069060
|
| --- /dev/null
|
| +++ b/device/nfc/android/java/src/org/chromium/device/nfc/NfcImpl.java
|
| @@ -0,0 +1,653 @@
|
| +// Copyright 2016 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +package org.chromium.device.nfc;
|
| +
|
| +import android.Manifest;
|
| +import android.app.Activity;
|
| +import android.app.PendingIntent;
|
| +import android.content.BroadcastReceiver;
|
| +import android.content.Context;
|
| +import android.content.Intent;
|
| +import android.content.IntentFilter;
|
| +import android.content.IntentFilter.MalformedMimeTypeException;
|
| +import android.content.pm.PackageManager;
|
| +import android.nfc.FormatException;
|
| +import android.nfc.NdefMessage;
|
| +import android.nfc.NdefRecord;
|
| +import android.nfc.NfcAdapter;
|
| +import android.nfc.NfcManager;
|
| +import android.nfc.Tag;
|
| +import android.nfc.TagLostException;
|
| +import android.nfc.tech.Ndef;
|
| +import android.nfc.tech.NdefFormatable;
|
| +import android.nfc.tech.TagTechnology;
|
| +import android.os.Build;
|
| +import android.os.Process;
|
| +import android.support.annotation.Nullable;
|
| +import android.support.v4.content.LocalBroadcastManager;
|
| +
|
| +import org.chromium.base.Log;
|
| +import org.chromium.mojo.bindings.Callbacks;
|
| +import org.chromium.mojo.system.MojoException;
|
| +import org.chromium.mojom.device.Nfc;
|
| +import org.chromium.mojom.device.NfcError;
|
| +import org.chromium.mojom.device.NfcErrorType;
|
| +import org.chromium.mojom.device.NfcMessage;
|
| +import org.chromium.mojom.device.NfcPushOptions;
|
| +import org.chromium.mojom.device.NfcPushTarget;
|
| +import org.chromium.mojom.device.NfcRecord;
|
| +import org.chromium.mojom.device.NfcRecordType;
|
| +import org.chromium.mojom.device.NfcWatchOptions;
|
| +
|
| +import java.io.IOException;
|
| +import java.io.UnsupportedEncodingException;
|
| +import java.util.ArrayList;
|
| +import java.util.List;
|
| +
|
| +/**
|
| + * Android implementation of the NFC mojo service defined in
|
| + * device/nfc/nfc.mojom.
|
| + */
|
| +public class NfcImpl extends BroadcastReceiver implements Nfc {
|
| + private static final String TAG = "NfcImpl";
|
| + private static final String DOMAIN = "w3.org";
|
| + private static final String TYPE = "webnfc";
|
| + private static final String TEXT_MIME = "text/plain";
|
| + private static final String JSON_MIME = "application/json";
|
| + private static final String OPAQUE_MIME = "application/octet-stream";
|
| + private static final String CHARSET_UTF8 = ";charset=UTF-8";
|
| + private static final String CHARSET_UTF16 = ";charset=UTF-16";
|
| +
|
| + /**
|
| + * Used to get instance of NFC adapter, @see android.nfc.NfcManager
|
| + */
|
| + private final NfcManager mNfcManager;
|
| +
|
| + /**
|
| + * NFC adapter. @see android.nfc.NfcAdapter
|
| + */
|
| + private final NfcAdapter mNfcAdapter;
|
| +
|
| + /**
|
| + * Activity object that is requred to enable / disable NFC reader mode operations.
|
| + */
|
| + private final Activity mActivity;
|
| +
|
| + /**
|
| + * Flag that indicates whether NFC permission is granted.
|
| + */
|
| + private final boolean mHasPermission;
|
| +
|
| + /**
|
| + * Object that contains data that was passed to method
|
| + * #push(NfcMessage message, NfcPushOptions options, PushResponse callback)
|
| + * @see PendingPushOperation
|
| + */
|
| + private PendingPushOperation mPendingPushOperation;
|
| +
|
| + /**
|
| + * Utility that provides I/O operations for a Tag. Created on demand when
|
| + * Tag is found. @see NfcTagWriter
|
| + */
|
| + private NfcTagWriter mTagWriter;
|
| +
|
| + /**
|
| + * Pending intent that is used for foreground dispatch.
|
| + * @see android.nfc.NfcAdapter.enableForegroundDispatch
|
| + */
|
| + private PendingIntent mPendingIntent;
|
| +
|
| + public NfcImpl(Activity activity) {
|
| + mActivity = activity;
|
| +
|
| + if (mActivity != null) {
|
| + int permission = mActivity.checkPermission(
|
| + Manifest.permission.NFC, Process.myPid(), Process.myUid());
|
| + mHasPermission = permission == PackageManager.PERMISSION_GRANTED;
|
| + } else {
|
| + mHasPermission = false;
|
| + }
|
| +
|
| + if (mHasPermission) {
|
| + mNfcManager = (NfcManager) mActivity.getSystemService(Context.NFC_SERVICE);
|
| + if (mNfcManager != null) {
|
| + mNfcAdapter = mNfcManager.getDefaultAdapter();
|
| + } else {
|
| + Log.w(TAG, "NFC is not supported.");
|
| + mNfcAdapter = null;
|
| + }
|
| + } else {
|
| + Log.w(TAG, "NFC operations are not permitted.");
|
| + mNfcAdapter = null;
|
| + mNfcManager = null;
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Pushes NfcMessage to Tag or Peer, whenever NFC device is in proximity.
|
| + * At the moment, only passive NFC devices are supported (NfcPushTarget.TAG).
|
| + *
|
| + * @param message that should be pushed to NFC device.
|
| + * @param options that contain information about timeout and target device type.
|
| + * @param callback that is used to notify when push operation is completed.
|
| + */
|
| + @Override
|
| + public void push(NfcMessage message, NfcPushOptions options, PushResponse callback) {
|
| + if (!checkIfReady(callback)) return;
|
| +
|
| + if (options.target == NfcPushTarget.PEER) {
|
| + callback.call(createError(NfcErrorType.NOT_SUPPORTED));
|
| + return;
|
| + }
|
| +
|
| + // If previous pending push operation is not completed, subsequent call
|
| + // should cancel pending operation.
|
| + if (mPendingPushOperation != null) {
|
| + mPendingPushOperation.complete(createError(NfcErrorType.OPERATION_CANCELLED));
|
| + }
|
| +
|
| + mPendingPushOperation = new PendingPushOperation(message, options, callback);
|
| + enableForegroundDispatch();
|
| + processPendingPushOperation();
|
| + }
|
| +
|
| + /**
|
| + * Cancels pending push operation.
|
| + * At the moment, only passive NFC devices are supported (NfcPushTarget.TAG).
|
| + *
|
| + * @param target @see NfcPushTarget
|
| + * @param callback that is used to notify caller when cancelPush() is completed.
|
| + */
|
| + @Override
|
| + public void cancelPush(int target, CancelPushResponse callback) {
|
| + if (!checkIfReady(callback)) return;
|
| +
|
| + if (target == NfcPushTarget.PEER) {
|
| + callback.call(createError(NfcErrorType.NOT_SUPPORTED));
|
| + return;
|
| + }
|
| +
|
| + if (mPendingPushOperation != null) {
|
| + mPendingPushOperation.complete(createError(NfcErrorType.OPERATION_CANCELLED));
|
| + mPendingPushOperation = null;
|
| + callback.call(null);
|
| + disableForegroundDispatch();
|
| + } else {
|
| + callback.call(createError(NfcErrorType.NOT_FOUND));
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Watch method allows to set filtering criteria for NfcMessages that are
|
| + * found when NFC device is within proximity. On success, watch ID is
|
| + * returned to caller through WatchResponse callback. When NfcMessage that
|
| + * matches NfcWatchOptions is found, it is returned through
|
| + * SubscribeToWatchEventsResponse callback interface.
|
| + * @see SubscribeToWatchEventsResponse
|
| + *
|
| + * @param options used to filter NfcMessages, @see NfcWatchOptions.
|
| + * @param callback that is used to notify caller when watch() is completed and return watch ID.
|
| + */
|
| + @Override
|
| + public void watch(NfcWatchOptions options, WatchResponse callback) {
|
| + if (!checkIfReady(callback)) return;
|
| + // TODO(shalamov): Not implemented.
|
| + callback.call(0, createError(NfcErrorType.NOT_SUPPORTED));
|
| + }
|
| +
|
| + /**
|
| + * Cancels NFC watch operation.
|
| + *
|
| + * @param id of watch operation.
|
| + * @param callback that is used to notify caller when cancelWatch() is completed.
|
| + */
|
| + @Override
|
| + public void cancelWatch(int id, CancelWatchResponse callback) {
|
| + if (!checkIfReady(callback)) return;
|
| + // TODO(shalamov): Not implemented.
|
| + callback.call(createError(NfcErrorType.NOT_SUPPORTED));
|
| + }
|
| +
|
| + /**
|
| + * Cancels all NFC watch operations.
|
| + *
|
| + * @param callback that is used to notify caller when cancelAllWatches() is completed.
|
| + */
|
| + @Override
|
| + public void cancelAllWatches(CancelAllWatchesResponse callback) {
|
| + if (!checkIfReady(callback)) return;
|
| + // TODO(shalamov): Not implemented.
|
| + callback.call(createError(NfcErrorType.NOT_SUPPORTED));
|
| + }
|
| +
|
| + @Override
|
| + public void subscribeToWatchEvents(SubscribeToWatchEventsResponse callback) {
|
| + // TODO(shalamov): Not implemented.
|
| + }
|
| +
|
| + /**
|
| + * Suspends all pending watch / push operations. Should be called when web
|
| + * page visibility is lost.
|
| + */
|
| + @Override
|
| + public void suspendNfcOperations() {
|
| + disableForegroundDispatch();
|
| + }
|
| +
|
| + /**
|
| + * Resumes all pending watch / push operations. Should be called when web
|
| + * page becomes visible.
|
| + */
|
| + @Override
|
| + public void resumeNfcOperations() {
|
| + if (mPendingPushOperation != null) enableForegroundDispatch();
|
| + }
|
| +
|
| + @Override
|
| + public void close() {
|
| + disableForegroundDispatch();
|
| + }
|
| +
|
| + @Override
|
| + public void onConnectionError(MojoException e) {
|
| + close();
|
| + }
|
| +
|
| + @Override
|
| + public void onReceive(Context context, Intent intent) {
|
| + Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
|
| + if (tag != null) onTagDiscovered(tag);
|
| + }
|
| +
|
| + /**
|
| + * Holds information about pending push operation.
|
| + */
|
| + private static class PendingPushOperation {
|
| + private final NfcMessage mNfcMessage;
|
| + private final NfcPushOptions mNfcPushOptions;
|
| + private final PushResponse mPushResponseCallback;
|
| +
|
| + public PendingPushOperation(
|
| + NfcMessage message, NfcPushOptions options, PushResponse callback) {
|
| + mNfcMessage = message;
|
| + mNfcPushOptions = options;
|
| + mPushResponseCallback = callback;
|
| + }
|
| +
|
| + /**
|
| + * Completes pending push operation.
|
| + *
|
| + * @param error should be null when operation is completed successfully,
|
| + * otherwise, error object with corresponding NfcErrorType must be provided.
|
| + */
|
| + public void complete(NfcError error) {
|
| + if (mPushResponseCallback != null) mPushResponseCallback.call(error);
|
| + }
|
| +
|
| + public NfcMessage message() {
|
| + return mNfcMessage;
|
| + }
|
| + public NfcPushOptions pushOptions() {
|
| + return mNfcPushOptions;
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Helper method that creates NfcError object from NfcErrorType.
|
| + *
|
| + * @param errorType @see NfcErrorType.
|
| + * @return NfcError
|
| + * @see NfcError
|
| + */
|
| + private NfcError createError(int errorType) {
|
| + NfcError error = new NfcError();
|
| + error.errorType = errorType;
|
| + return error;
|
| + }
|
| +
|
| + /**
|
| + * Checks if NFC funcionality can be used by the mojo service.
|
| + * If permission to use NFC is granted and hardware is enabled, returns null.
|
| + *
|
| + * @return NfcError
|
| + */
|
| + @Nullable
|
| + private NfcError checkIfReady() {
|
| + if (!mHasPermission) {
|
| + return createError(NfcErrorType.SECURITY);
|
| + } else if (mNfcManager == null || mNfcAdapter == null
|
| + || Build.VERSION.SDK_INT < Build.VERSION_CODES.GINGERBREAD_MR1) {
|
| + return createError(NfcErrorType.NOT_SUPPORTED);
|
| + } else if (!mNfcAdapter.isEnabled()) {
|
| + return createError(NfcErrorType.DEVICE_DISABLED);
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + /**
|
| + * Uses checkIfReady() method and if NFC functionality cannot be used,
|
| + * calls mojo callback with NfcError.
|
| + *
|
| + * @param WatchResponse Callback that is provided to watch() method.
|
| + * @return boolean true if NFC functionality can be used, false otherwise.
|
| + */
|
| + private boolean checkIfReady(WatchResponse callback) {
|
| + NfcError error = checkIfReady();
|
| + if (error == null) return true;
|
| + callback.call(0, error);
|
| + return false;
|
| + }
|
| +
|
| + /**
|
| + * Uses checkIfReady() method and if NFC functionality cannot be used,
|
| + * calls mojo callback NfcError.
|
| + *
|
| + * @param callback Generic callback that is provided to push(), cancelPush(),
|
| + * cancelWatch() and cancelAllWatches() methods.
|
| + * @return boolean true if NFC functionality can be used, false otherwise.
|
| + */
|
| + private boolean checkIfReady(Callbacks.Callback1<NfcError> callback) {
|
| + NfcError error = checkIfReady();
|
| + if (error == null) return true;
|
| + callback.call(error);
|
| + return false;
|
| + }
|
| +
|
| + /**
|
| + * Enables foreground dispatch.
|
| + */
|
| + private void enableForegroundDispatch() {
|
| + if (mPendingIntent == null) {
|
| + mPendingIntent = PendingIntent.getActivity(mActivity, 0,
|
| + new Intent(mActivity, mActivity.getClass())
|
| + .addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP),
|
| + 0);
|
| +
|
| + List<IntentFilter> filters = new ArrayList<IntentFilter>();
|
| + IntentFilter tag_filter = new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED);
|
| + IntentFilter ndef_filter = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
|
| + filters.add(tag_filter);
|
| +
|
| + try {
|
| + ndef_filter.addDataType(TEXT_MIME);
|
| + ndef_filter.addDataType(JSON_MIME);
|
| + ndef_filter.addDataType(OPAQUE_MIME);
|
| + filters.add(ndef_filter);
|
| + } catch (MalformedMimeTypeException e) {
|
| + Log.w(TAG, "Invalid MIME type was provided to Intent filter.");
|
| + ndef_filter = null;
|
| + }
|
| +
|
| + IntentFilter[] filterArray = new IntentFilter[filters.size()];
|
| + filters.toArray(filterArray);
|
| +
|
| + String[][] techLists = new String[][] {
|
| + new String[] {Ndef.class.getName(), NdefFormatable.class.getName()}};
|
| +
|
| + LocalBroadcastManager manager = LocalBroadcastManager.getInstance(mActivity);
|
| + manager.registerReceiver(this, tag_filter);
|
| + if (ndef_filter != null) manager.registerReceiver(this, ndef_filter);
|
| + mNfcAdapter.enableForegroundDispatch(mActivity, mPendingIntent, filterArray, techLists);
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Disables foreground dispatch.
|
| + */
|
| + private void disableForegroundDispatch() {
|
| + if (mPendingIntent != null) {
|
| + mNfcAdapter.disableForegroundDispatch(mActivity);
|
| + LocalBroadcastManager manager = LocalBroadcastManager.getInstance(mActivity);
|
| + manager.unregisterReceiver(this);
|
| + mPendingIntent = null;
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * NdefFormatable and Ndef interfaces have different signatures for writing
|
| + * NdefMessage to a tag. This interface provides generic write method.
|
| + */
|
| + private interface TagTechnologyWriter {
|
| + public void write(NdefMessage message)
|
| + throws IOException, TagLostException, FormatException;
|
| + }
|
| +
|
| + /**
|
| + * Implementation of TagTechnologyWriter that can write NdefMessage to NFC tag.
|
| + */
|
| + private static class NdefWriter implements TagTechnologyWriter {
|
| + private final Ndef mNdef;
|
| +
|
| + NdefWriter(Ndef ndef) {
|
| + mNdef = ndef;
|
| + }
|
| +
|
| + public void write(NdefMessage message)
|
| + throws IOException, TagLostException, FormatException {
|
| + mNdef.writeNdefMessage(message);
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Implementation of TagTechnologyWriter that can format empty NFC tag
|
| + * with provided NFCMessage.
|
| + */
|
| + private static class NdefFormattableWriter implements TagTechnologyWriter {
|
| + private final NdefFormatable mNdefFormattable;
|
| +
|
| + NdefFormattableWriter(NdefFormatable ndefFormattable) {
|
| + mNdefFormattable = ndefFormattable;
|
| + }
|
| +
|
| + public void write(NdefMessage message)
|
| + throws IOException, TagLostException, FormatException {
|
| + mNdefFormattable.format(message);
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Utility class that holds TagTechnology and TagTechnologyWriter objects.
|
| + * Provides connectivity and I/O related operations for NFC tag.
|
| + */
|
| + private static class NfcTagWriter {
|
| + private final TagTechnology mTech;
|
| + private final TagTechnologyWriter mTechWriter;
|
| + private boolean mWasConnected = false;
|
| +
|
| + /**
|
| + * Factory method that creates NfcTagWriter with TagTechnologyWriter
|
| + * appropriate for a given NFC Tag.
|
| + *
|
| + * @param tag @see android.nfc.Tag
|
| + * @return NfcTagWriter or null when unsupported Tag is provided.
|
| + */
|
| + public static NfcTagWriter create(Tag tag) {
|
| + if (tag == null) return null;
|
| +
|
| + Ndef ndef = Ndef.get(tag);
|
| + if (ndef != null) return new NfcTagWriter(ndef, new NdefWriter(ndef));
|
| +
|
| + NdefFormatable formattable = NdefFormatable.get(tag);
|
| + if (formattable != null) {
|
| + return new NfcTagWriter(formattable, new NdefFormattableWriter(formattable));
|
| + }
|
| +
|
| + return null;
|
| + }
|
| +
|
| + private NfcTagWriter(TagTechnology tech, TagTechnologyWriter writer) {
|
| + mTech = tech;
|
| + mTechWriter = writer;
|
| + }
|
| +
|
| + /**
|
| + * Connects to NFC tag.
|
| + */
|
| + public void connect() throws IOException, TagLostException {
|
| + if (!mTech.isConnected()) {
|
| + mTech.connect();
|
| + mWasConnected = true;
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Closes connection.
|
| + */
|
| + public void close() throws IOException {
|
| + mTech.close();
|
| + }
|
| +
|
| + /**
|
| + * Writes NdefMessage to NFC tag.
|
| + *
|
| + * @param message @see android.nfc.NdefMessage
|
| + */
|
| + public void write(NdefMessage message)
|
| + throws IOException, TagLostException, FormatException {
|
| + mTechWriter.write(message);
|
| + }
|
| +
|
| + /**
|
| + * If tag was previously connected and subsequent connection to the same
|
| + * tag fails, consider tag to be out of ragne.
|
| + */
|
| + public boolean isTagOutOfRange() {
|
| + try {
|
| + connect();
|
| + } catch (IOException e) {
|
| + return mWasConnected;
|
| + }
|
| + return false;
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Exception that is raised when mojo NfcMessage cannot be coverted to NdefMessage.
|
| + */
|
| + private static class InvalidMessageException extends Exception {}
|
| +
|
| + /**
|
| + * Converts mojo NfcMessage to android.nfc.NdefMessage.
|
| + *
|
| + * @param message mojo NfcMessage
|
| + * @return NdefMessage
|
| + * @see android.nfc.NdefMessage
|
| + */
|
| + private NdefMessage toNdefMessage(NfcMessage message) throws InvalidMessageException {
|
| + if (message == null || message.data.length == 0) throw new InvalidMessageException();
|
| +
|
| + try {
|
| + List<NdefRecord> records = new ArrayList<NdefRecord>();
|
| + for (NfcRecord record : message.data) {
|
| + records.add(toNdefRecord(record));
|
| + }
|
| + records.add(NdefRecord.createExternal(DOMAIN, TYPE, message.url.getBytes()));
|
| + NdefRecord[] ndefRecords = new NdefRecord[records.size()];
|
| + records.toArray(ndefRecords);
|
| + return new NdefMessage(ndefRecords);
|
| + } catch (UnsupportedEncodingException | InvalidMessageException
|
| + | IllegalArgumentException e) {
|
| + throw new InvalidMessageException();
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Returns charset of mojo NfcRecord. Only applicable for URL and TEXT records.
|
| + * If charset cannot be determined, UTF-8 charset is used by default.
|
| + *
|
| + * @param record
|
| + * @return String
|
| + */
|
| + private String getCharset(NfcRecord record) {
|
| + if (record.mediaType.endsWith(CHARSET_UTF8)) return "UTF-8";
|
| +
|
| + if (record.mediaType.endsWith(CHARSET_UTF16)) return "UTF-16LE";
|
| +
|
| + Log.w(TAG, "Unknown charset, defaulting to UTF-8.");
|
| + return "UTF-8";
|
| + }
|
| +
|
| + /**
|
| + * Converts mojo NfcRecord to android.nfc.NdefRecord.
|
| + *
|
| + * @param record mojo NfcRecord
|
| + * @return NdefRecord
|
| + * @see android.nfc.NdefRecord
|
| + */
|
| + private NdefRecord toNdefRecord(NfcRecord record)
|
| + throws InvalidMessageException, IllegalArgumentException, UnsupportedEncodingException {
|
| + switch (record.recordType) {
|
| + case NfcRecordType.URL:
|
| + return NdefRecord.createUri(new String(record.data, getCharset(record)));
|
| + case NfcRecordType.TEXT:
|
| + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
| + return NdefRecord.createTextRecord(
|
| + "en-US", new String(record.data, getCharset(record)));
|
| + } else {
|
| + return NdefRecord.createMime(TEXT_MIME, record.data);
|
| + }
|
| + case NfcRecordType.JSON:
|
| + case NfcRecordType.OPAQUE_RECORD:
|
| + return NdefRecord.createMime(record.mediaType, record.data);
|
| + default:
|
| + throw new InvalidMessageException();
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Completes pending push operation. On error, invalidates #mTagWriter.
|
| + *
|
| + * @param error
|
| + */
|
| + private void pendingPushOperationCompleted(NfcError error) {
|
| + if (mPendingPushOperation != null) {
|
| + mPendingPushOperation.complete(error);
|
| + mPendingPushOperation = null;
|
| + }
|
| +
|
| + if (error != null) mTagWriter = null;
|
| + }
|
| +
|
| + /**
|
| + * Checks whether there is a #mPendingPushOperation and writes data to NFC tag.
|
| + * In case of exception calls pendingPushOperationCompleted() with appropriate
|
| + * error object.
|
| + */
|
| + private void processPendingPushOperation() {
|
| + if (mTagWriter == null || mPendingPushOperation == null) return;
|
| +
|
| + if (mTagWriter.isTagOutOfRange()) {
|
| + mTagWriter = null;
|
| + return;
|
| + }
|
| +
|
| + try {
|
| + mTagWriter.connect();
|
| + mTagWriter.write(toNdefMessage(mPendingPushOperation.message()));
|
| + pendingPushOperationCompleted(null);
|
| + mTagWriter.close();
|
| + } catch (InvalidMessageException e) {
|
| + Log.w(TAG, "Cannot write data to NFC tag. Invalid NfcMessage.");
|
| + pendingPushOperationCompleted(createError(NfcErrorType.INVALID_MESSAGE));
|
| + } catch (TagLostException e) {
|
| + Log.w(TAG, "Cannot write data to NFC tag. Tag is lost.");
|
| + pendingPushOperationCompleted(createError(NfcErrorType.IO_ERROR));
|
| + } catch (FormatException | IOException e) {
|
| + Log.w(TAG, "Cannot write data to NFC tag. IO_ERROR.");
|
| + pendingPushOperationCompleted(createError(NfcErrorType.IO_ERROR));
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Called by ReaderCallbackHandler when NFC tag is in proximity.
|
| + * calls processPendingPushOperation() that will write data to a tag.
|
| + *
|
| + * @param tag
|
| + */
|
| + private void onTagDiscovered(Tag tag) {
|
| + mTagWriter = NfcTagWriter.create(tag);
|
| + processPendingPushOperation();
|
| + }
|
| +}
|
|
|