Chromium Code Reviews| 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..05f8fce65fb6ddd6823abb1f7f4f9efe704d5d8a |
| --- /dev/null |
| +++ b/device/nfc/android/java/src/org/chromium/device/nfc/NfcImpl.java |
| @@ -0,0 +1,643 @@ |
| +// 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.annotation.TargetApi; |
| +import android.app.Activity; |
| +import android.content.Context; |
| +import android.content.pm.PackageManager; |
| +import android.nfc.FormatException; |
| +import android.nfc.NdefMessage; |
| +import android.nfc.NdefRecord; |
| +import android.nfc.NfcAdapter; |
| +import android.nfc.NfcAdapter.ReaderCallback; |
| +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 org.chromium.base.ApplicationStatus; |
| +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.NfcClient; |
| +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 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 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; |
| + |
| + /** |
| + * Context that is pasesed to NFC mojo service. Used to check permissions |
|
Ted C
2016/04/28 17:27:22
line wrapping for comments should be 100 in java
shalamov
2016/05/11 14:09:57
Done.
|
| + * and get Android NFC system service. |
| + */ |
| + private final Context mContext; |
| + |
| + /** |
| + * 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; |
| + |
| + /** |
| + * Implementation of android.nfc.NfcAdapter.ReaderCallback. @see ReaderCallbackHandler |
| + */ |
| + private ReaderCallbackHandler mReaderCallbackHandler; |
| + |
| + /** |
| + * 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; |
| + |
| + public NfcImpl(Context context) { |
| + mContext = context; |
| + int permission = |
| + context.checkPermission(Manifest.permission.NFC, Process.myPid(), Process.myUid()); |
| + mHasPermission = permission == PackageManager.PERMISSION_GRANTED; |
| + if (mHasPermission) { |
| + mActivity = ApplicationStatus.getLastTrackedFocusedActivity(); |
|
Ted C
2016/04/28 17:27:22
we should really avoid using this call if at all p
shalamov
2016/05/11 14:09:57
Done.
|
| + mNfcManager = (NfcManager) mContext.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; |
| + mActivity = null; |
| + } |
| + } |
| + |
| + /** |
| + * Sets NfcClient. NfcClient interface is used to notify mojo NFC service |
| + * client when NFC device is in proximity and has NfcMessage that matches |
| + * NfcWatchOptions criteria. |
| + * @see Nfc#watch(NfcWatchOptions options, WatchResponse callback) |
| + * |
| + * @param client @see NfcClient |
| + */ |
| + @Override |
| + public void setClient(NfcClient client) { |
| + // todo(shalamov): Should be implemented when watch() is implemented. |
|
Ted C
2016/04/28 17:27:21
nit, TODO should be capitalized
shalamov
2016/05/11 14:09:57
Done.
|
| + } |
| + |
| + /** |
| + * 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); |
| + enableReaderMode(); |
|
Ted C
2016/04/28 17:27:22
as far as I can tell, push only works if Android i
|
| + 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); |
| + disableReaderMode(); |
| + } 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 passed to NfcClient interface |
| + * together with corresponding watch ID. |
| + * @see NfcClient#onWatch(int id, NfcMessage message) |
| + * |
| + * @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)); |
| + } |
| + |
| + /** |
| + * Suspends all pending watch / push operations. Should be called when web |
| + * page visibility is lost. |
| + */ |
| + @Override |
| + public void suspendNfcOperations() { |
| + // todo(shalamov): Not implemented. |
| + } |
| + |
| + /** |
| + * Resumes all pending watch / push operations. Should be called when web |
| + * page becomes visible. |
| + */ |
| + @Override |
| + public void resumeNfcOperations() { |
| + // todo(shalamov): Not implemented. |
| + } |
| + |
| + @Override |
| + public void close() {} |
|
Ted C
2016/04/28 17:27:22
what close is this associated with?
To me, it loo
shalamov
2016/05/11 14:09:57
Done.
|
| + |
| + @Override |
| + public void onConnectionError(MojoException e) {} |
| + |
| + /** |
| + * 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. |
|
Ted C
2016/04/28 17:27:22
align w/ should above
shalamov
2016/05/11 14:09:57
Done.
|
| + */ |
| + public void complete(NfcError error) { |
| + if (mPushResponseCallback != null) mPushResponseCallback.call(error); |
| + } |
| + |
| + public NfcMessage message() { |
| + return mNfcMessage; |
| + } |
| + public NfcPushOptions pushOptions() { |
|
Ted C
2016/04/28 17:27:22
add a blank line above this.
Also, you could make
shalamov
2016/05/11 14:09:57
Done.
|
| + 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.KITKAT) { |
|
Ted C
2016/04/28 17:27:21
I would still not create the mNfcManager for KK.
shalamov
2016/05/11 14:09:57
Done.
|
| + 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; |
| + } |
| + |
| + /** |
| + * Implementation of android.nfc.NfcAdapter.ReaderCallback. |
| + * Callback is called when NFC tag is discovered, Tag object is delegated |
| + * to mojo service implementation method NfcImpl.onTagDiscovered(). |
| + */ |
| + @TargetApi(Build.VERSION_CODES.KITKAT) |
| + private static class ReaderCallbackHandler implements ReaderCallback { |
| + private final NfcImpl mNfcImpl; |
| + |
| + public ReaderCallbackHandler(NfcImpl impl) { |
| + mNfcImpl = impl; |
| + } |
| + |
| + @Override |
| + public void onTagDiscovered(Tag tag) { |
| + mNfcImpl.onTagDiscovered(tag); |
| + } |
| + } |
| + |
| + /** |
| + * Enables reader mode, allowing NFC device to read / write NFC tags. |
| + * @see android.nfc.NfcAdapter#enableReaderMode |
| + */ |
| + private void enableReaderMode() { |
| + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return; |
| + if (mReaderCallbackHandler != null) return; |
| + |
| + mReaderCallbackHandler = new ReaderCallbackHandler(this); |
| + mNfcAdapter.enableReaderMode(mActivity, mReaderCallbackHandler, |
| + NfcAdapter.FLAG_READER_NFC_A | NfcAdapter.FLAG_READER_NFC_B |
| + | NfcAdapter.FLAG_READER_NFC_F | NfcAdapter.FLAG_READER_NFC_V, |
| + null); |
| + } |
| + |
| + /** |
| + * Disables reader mode. |
| + * @see android.nfc.NfcAdapter#disableReaderMode |
| + */ |
| + private void disableReaderMode() { |
| + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return; |
| + |
| + mReaderCallbackHandler = null; |
| + mNfcAdapter.disableReaderMode(mActivity); |
| + } |
| + |
| + /** |
| + * 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; |
|
Ted C
2016/04/28 17:27:22
false is the default, so you can drop this
shalamov
2016/05/11 14:09:58
Done.
|
| + |
| + /** |
| + * 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) { |
|
Ted C
2016/04/28 17:27:21
is message.data an array primitive? In general, t
shalamov
2016/05/11 14:09:57
Done.
|
| + 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 |
|
Ted C
2016/04/28 17:27:21
these are a bit terse...you can probably drop thes
shalamov
2016/05/11 14:09:57
Done.
|
| + * @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 |
|
Ted C
2016/04/28 17:27:22
same...you can drop all of these empty javadoc par
shalamov
2016/05/11 14:09:58
Done.
|
| + */ |
| + 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 |
| + */ |
| + public void onTagDiscovered(Tag tag) { |
| + mTagWriter = NfcTagWriter.create(tag); |
| + processPendingPushOperation(); |
| + } |
| +} |