Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(272)

Unified Diff: device/nfc/android/java/src/org/chromium/device/nfc/NfcImpl.java

Issue 1765533004: [webnfc] Implement watch method for Android nfc mojo service. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@implement_nfc_watch_in_blink
Patch Set: Rebased to master Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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
index b74902e021ba4aaa8bb2c419cbb86338cb7ee859..ba2aef35f8f22d4a6831b4d0c18637cc45a05e9f 100644
--- a/device/nfc/android/java/src/org/chromium/device/nfc/NfcImpl.java
+++ b/device/nfc/android/java/src/org/chromium/device/nfc/NfcImpl.java
@@ -10,6 +10,7 @@ import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.nfc.FormatException;
+import android.nfc.NdefMessage;
import android.nfc.NfcAdapter;
import android.nfc.NfcAdapter.ReaderCallback;
import android.nfc.NfcManager;
@@ -17,6 +18,7 @@ import android.nfc.Tag;
import android.nfc.TagLostException;
import android.os.Build;
import android.os.Process;
+import android.util.SparseArray;
import org.chromium.base.Log;
import org.chromium.device.nfc.mojom.Nfc;
@@ -26,11 +28,15 @@ import org.chromium.device.nfc.mojom.NfcErrorType;
import org.chromium.device.nfc.mojom.NfcMessage;
import org.chromium.device.nfc.mojom.NfcPushOptions;
import org.chromium.device.nfc.mojom.NfcPushTarget;
+import org.chromium.device.nfc.mojom.NfcWatchMode;
import org.chromium.device.nfc.mojom.NfcWatchOptions;
import org.chromium.mojo.bindings.Callbacks;
import org.chromium.mojo.system.MojoException;
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
@@ -78,6 +84,25 @@ public class NfcImpl implements Nfc {
*/
private NfcTagHandler mTagHandler;
+ /**
+ * Client interface used to deliver NFCMessages for registered watch operations.
+ * @see #watch
+ */
+ private NfcClient mClient;
+
+ /**
+ * Watcher id that is incremented for each #watch call.
+ */
+ private int mWatcherId;
+
+ /**
+ * Map of watchId <-> NfcWatchOptions. All NfcWatchOptions are matched against tag that is in
+ * proximity, when match algorithm (@see #matchesWatchOptions) returns true, watcher with
+ * corresponding ID would be notified using NfcClient interface.
+ * @see NfcClient#onWatch(int[] id, NfcMessage message)
+ */
+ private final SparseArray<NfcWatchOptions> mWatchers = new SparseArray<>();
+
public NfcImpl(Context context) {
int permission =
context.checkPermission(Manifest.permission.NFC, Process.myPid(), Process.myUid());
@@ -105,7 +130,7 @@ public class NfcImpl implements Nfc {
protected void setActivity(Activity activity) {
disableReaderMode();
mActivity = activity;
- enableReaderMode();
+ enableReaderModeIfNeeded();
}
/**
@@ -117,7 +142,7 @@ public class NfcImpl implements Nfc {
*/
@Override
public void setClient(NfcClient client) {
- // TODO(crbug.com/625589): Should be implemented when watch() is implemented.
+ mClient = client;
dcheng 2016/11/28 19:46:40 Can we file a bug to get rid of this? Ideally, we
shalamov 2016/11/29 13:07:22 Thank you for looking Daniel, unfortunately, I'm n
}
/**
@@ -132,6 +157,11 @@ public class NfcImpl implements Nfc {
public void push(NfcMessage message, NfcPushOptions options, PushResponse callback) {
if (!checkIfReady(callback)) return;
+ if (!NfcMessageValidator.isValid(message)) {
+ callback.call(createError(NfcErrorType.INVALID_MESSAGE));
+ return;
+ }
+
if (options.target == NfcPushTarget.PEER) {
callback.call(createError(NfcErrorType.NOT_SUPPORTED));
return;
@@ -143,7 +173,7 @@ public class NfcImpl implements Nfc {
}
mPendingPushOperation = new PendingPushOperation(message, options, callback);
- enableReaderMode();
+ enableReaderModeIfNeeded();
processPendingPushOperation();
}
@@ -169,7 +199,7 @@ public class NfcImpl implements Nfc {
mPendingPushOperation.complete(createError(NfcErrorType.OPERATION_CANCELLED));
mPendingPushOperation = null;
callback.call(null);
- disableReaderMode();
+ disableReaderModeIfNeeded();
}
}
@@ -186,8 +216,11 @@ public class NfcImpl implements Nfc {
@Override
public void watch(NfcWatchOptions options, WatchResponse callback) {
if (!checkIfReady(callback)) return;
- // TODO(crbug.com/625589): Not implemented.
- callback.call(0, createError(NfcErrorType.NOT_SUPPORTED));
+ int watcherId = ++mWatcherId;
+ mWatchers.put(watcherId, options);
+ callback.call(watcherId, null);
+ enableReaderModeIfNeeded();
+ processPendingWatchOperations();
}
/**
@@ -199,8 +232,14 @@ public class NfcImpl implements Nfc {
@Override
public void cancelWatch(int id, CancelWatchResponse callback) {
if (!checkIfReady(callback)) return;
- // TODO(crbug.com/625589): Not implemented.
- callback.call(createError(NfcErrorType.NOT_SUPPORTED));
+
+ if (mWatchers.indexOfKey(id) < 0) {
+ callback.call(createError(NfcErrorType.NOT_FOUND));
+ } else {
+ mWatchers.remove(id);
+ callback.call(null);
+ disableReaderModeIfNeeded();
+ }
}
/**
@@ -211,8 +250,14 @@ public class NfcImpl implements Nfc {
@Override
public void cancelAllWatches(CancelAllWatchesResponse callback) {
if (!checkIfReady(callback)) return;
- // TODO(crbug.com/625589): Not implemented.
- callback.call(createError(NfcErrorType.NOT_SUPPORTED));
+
+ if (mWatchers.size() == 0) {
+ callback.call(createError(NfcErrorType.NOT_FOUND));
+ } else {
+ mWatchers.clear();
+ callback.call(null);
+ disableReaderModeIfNeeded();
+ }
}
/**
@@ -228,7 +273,7 @@ public class NfcImpl implements Nfc {
*/
@Override
public void resumeNfcOperations() {
- enableReaderMode();
+ enableReaderModeIfNeeded();
}
@Override
@@ -343,13 +388,13 @@ public class NfcImpl implements Nfc {
* Enables reader mode, allowing NFC device to read / write NFC tags.
* @see android.nfc.NfcAdapter#enableReaderMode
*/
- private void enableReaderMode() {
+ private void enableReaderModeIfNeeded() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return;
if (mReaderCallbackHandler != null || mActivity == null || mNfcAdapter == null) return;
- // TODO(crbug.com/625589): Check if there are active watch operations.
- if (mPendingPushOperation == null) return;
+ // Do not enable reader mode, if there are no active push / watch operations.
+ if (mPendingPushOperation == null && mWatchers.size() == 0) return;
mReaderCallbackHandler = new ReaderCallbackHandler(this);
mNfcAdapter.enableReaderMode(mActivity, mReaderCallbackHandler,
@@ -377,16 +422,23 @@ public class NfcImpl implements Nfc {
}
/**
+ * Checks if there are pending push / watch operations and disables readre mode
+ * whenever necessary.
+ */
+ private void disableReaderModeIfNeeded() {
+ if (mPendingPushOperation == null && mWatchers.size() == 0) {
+ disableReaderMode();
+ }
+ }
+
+ /**
* Completes pending push operation. On error, invalidates #mTagHandler.
*/
private void pendingPushOperationCompleted(NfcError error) {
if (mPendingPushOperation != null) {
mPendingPushOperation.complete(error);
mPendingPushOperation = null;
-
- // TODO(crbug.com/625589): When nfc.watch is implemented, disable reader mode
- // only when there are no active watch operations.
- disableReaderMode();
+ disableReaderModeIfNeeded();
}
if (error != null) mTagHandler = null;
@@ -408,7 +460,6 @@ public class NfcImpl implements Nfc {
mTagHandler.connect();
mTagHandler.write(NfcTypeConverter.toNdefMessage(mPendingPushOperation.nfcMessage));
pendingPushOperationCompleted(null);
- mTagHandler.close();
} catch (InvalidNfcMessageException e) {
Log.w(TAG, "Cannot write data to NFC tag. Invalid NfcMessage.");
pendingPushOperationCompleted(createError(NfcErrorType.INVALID_MESSAGE));
@@ -422,10 +473,130 @@ public class NfcImpl implements Nfc {
}
/**
+ * Reads NfcMessage from a tag and forwards message to matching method.
+ */
+ private void processPendingWatchOperations() {
+ if (mTagHandler == null || mClient == null || mWatchers.size() == 0) return;
+
+ // Skip reading if there is a pending push operation and ignoreRead flag is set.
+ if (mPendingPushOperation != null && mPendingPushOperation.nfcPushOptions.ignoreRead) {
+ return;
+ }
+
+ if (mTagHandler.isTagOutOfRange()) {
+ mTagHandler = null;
+ return;
+ }
+
+ NdefMessage message = null;
+
+ try {
+ mTagHandler.connect();
+ message = mTagHandler.read();
+ if (message.getByteArrayLength() > NfcMessage.MAX_SIZE) {
+ Log.w(TAG, "Cannot read data from NFC tag. NfcMessage exceeds allowed size.");
+ return;
+ }
+ } catch (TagLostException e) {
+ Log.w(TAG, "Cannot read data from NFC tag. Tag is lost.");
+ } catch (FormatException | IOException e) {
+ Log.w(TAG, "Cannot read data from NFC tag. IO_ERROR.");
+ }
+
+ if (message != null) notifyMatchingWatchers(message);
+ }
+
+ /**
+ * Iterates through active watchers and if any of those match NfcWatchOptions criteria,
+ * delivers NfcMessage to the client.
+ */
+ private void notifyMatchingWatchers(NdefMessage message) {
+ try {
+ NfcMessage nfcMessage = NfcTypeConverter.toNfcMessage(message);
+ List<Integer> watchIds = new ArrayList<Integer>();
+ for (int i = 0; i < mWatchers.size(); i++) {
+ NfcWatchOptions options = mWatchers.valueAt(i);
+ if (matchesWatchOptions(nfcMessage, options)) watchIds.add(mWatchers.keyAt(i));
+ }
+
+ if (watchIds.size() != 0) {
+ int[] ids = new int[watchIds.size()];
+ for (int i = 0; i < watchIds.size(); ++i) {
+ ids[i] = watchIds.get(i).intValue();
+ }
+ mClient.onWatch(ids, nfcMessage);
+ }
+ } catch (UnsupportedEncodingException e) {
+ Log.w(TAG, "Cannot convert NdefMessage to NfcMessage.");
+ }
+ }
+
+ /**
+ * Implements matching algorithm.
+ */
+ private boolean matchesWatchOptions(NfcMessage message, NfcWatchOptions options) {
+ // Valid WebNFC message must have non-empty url.
+ if (options.mode == NfcWatchMode.WEBNFC_ONLY
+ && (message.url == null || message.url.isEmpty())) {
+ return false;
+ }
+
+ // Filter by NfcMessage.url
+ if (options.url != null && !options.url.isEmpty() && !options.url.equals(message.url)) {
+ return false;
+ }
+
+ // Matches any record / media type.
+ if ((options.mediaType == null || options.mediaType.isEmpty())
+ && options.recordFilter == null) {
+ return true;
+ }
+
+ // Filter by mediaType and recordType
+ for (int i = 0; i < message.data.length; i++) {
+ boolean matchedMediaType;
+ boolean matchedRecordType;
+
+ if (options.mediaType == null || options.mediaType.isEmpty()) {
+ // If media type for the watch options is empty, match all media types.
+ matchedMediaType = true;
+ } else {
+ matchedMediaType = options.mediaType.equals(message.data[i].mediaType);
+ }
+
+ if (options.recordFilter == null) {
+ // If record type filter for the watch options is null, match all record types.
+ matchedRecordType = true;
+ } else {
+ matchedRecordType = options.recordFilter.recordType == message.data[i].recordType;
+ }
+
+ if (matchedMediaType && matchedRecordType) return true;
+ }
+
+ return false;
+ }
+
+ /**
* Called by ReaderCallbackHandler when NFC tag is in proximity.
*/
public void onTagDiscovered(Tag tag) {
- mTagHandler = NfcTagHandler.create(tag);
+ processPendingOperations(NfcTagHandler.create(tag));
+ }
+
+ /**
+ * Processes pending operation when NFC tag is in proximity.
+ */
+ protected void processPendingOperations(NfcTagHandler tagHandler) {
+ mTagHandler = tagHandler;
+ processPendingWatchOperations();
processPendingPushOperation();
+ if (mTagHandler != null && mTagHandler.isConnected()) {
+ try {
+ mTagHandler.close();
+ } catch (IOException e) {
+ Log.w(TAG, "Cannot close NFC tag connection.");
+ }
+ }
}
}
« no previous file with comments | « device/nfc/android/BUILD.gn ('k') | device/nfc/android/java/src/org/chromium/device/nfc/NfcMessageValidator.java » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698