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

Side by Side 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: Fixes for Reilly's comments Created 4 years, 2 months 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 unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 package org.chromium.device.nfc; 5 package org.chromium.device.nfc;
6 6
7 import android.Manifest; 7 import android.Manifest;
8 import android.annotation.TargetApi; 8 import android.annotation.TargetApi;
9 import android.app.Activity; 9 import android.app.Activity;
10 import android.content.Context; 10 import android.content.Context;
11 import android.content.pm.PackageManager; 11 import android.content.pm.PackageManager;
12 import android.nfc.FormatException; 12 import android.nfc.FormatException;
13 import android.nfc.NdefMessage;
13 import android.nfc.NfcAdapter; 14 import android.nfc.NfcAdapter;
14 import android.nfc.NfcAdapter.ReaderCallback; 15 import android.nfc.NfcAdapter.ReaderCallback;
15 import android.nfc.NfcManager; 16 import android.nfc.NfcManager;
16 import android.nfc.Tag; 17 import android.nfc.Tag;
17 import android.nfc.TagLostException; 18 import android.nfc.TagLostException;
18 import android.os.Build; 19 import android.os.Build;
19 import android.os.Process; 20 import android.os.Process;
21 import android.util.SparseArray;
20 22
21 import org.chromium.base.Log; 23 import org.chromium.base.Log;
22 import org.chromium.device.nfc.mojom.Nfc; 24 import org.chromium.device.nfc.mojom.Nfc;
23 import org.chromium.device.nfc.mojom.NfcClient; 25 import org.chromium.device.nfc.mojom.NfcClient;
24 import org.chromium.device.nfc.mojom.NfcError; 26 import org.chromium.device.nfc.mojom.NfcError;
25 import org.chromium.device.nfc.mojom.NfcErrorType; 27 import org.chromium.device.nfc.mojom.NfcErrorType;
26 import org.chromium.device.nfc.mojom.NfcMessage; 28 import org.chromium.device.nfc.mojom.NfcMessage;
27 import org.chromium.device.nfc.mojom.NfcPushOptions; 29 import org.chromium.device.nfc.mojom.NfcPushOptions;
28 import org.chromium.device.nfc.mojom.NfcPushTarget; 30 import org.chromium.device.nfc.mojom.NfcPushTarget;
31 import org.chromium.device.nfc.mojom.NfcWatchMode;
29 import org.chromium.device.nfc.mojom.NfcWatchOptions; 32 import org.chromium.device.nfc.mojom.NfcWatchOptions;
30 import org.chromium.mojo.bindings.Callbacks; 33 import org.chromium.mojo.bindings.Callbacks;
31 import org.chromium.mojo.system.MojoException; 34 import org.chromium.mojo.system.MojoException;
32 35
33 import java.io.IOException; 36 import java.io.IOException;
37 import java.io.UnsupportedEncodingException;
38 import java.util.ArrayList;
39 import java.util.List;
34 40
35 /** 41 /**
36 * Android implementation of the NFC mojo service defined in 42 * Android implementation of the NFC mojo service defined in
37 * device/nfc/nfc.mojom. 43 * device/nfc/nfc.mojom.
38 */ 44 */
39 public class NfcImpl implements Nfc { 45 public class NfcImpl implements Nfc {
40 private static final String TAG = "NfcImpl"; 46 private static final String TAG = "NfcImpl";
41 47
42 /** 48 /**
43 * Used to get instance of NFC adapter, @see android.nfc.NfcManager 49 * Used to get instance of NFC adapter, @see android.nfc.NfcManager
(...skipping 27 matching lines...) Expand all
71 * @see PendingPushOperation 77 * @see PendingPushOperation
72 */ 78 */
73 private PendingPushOperation mPendingPushOperation; 79 private PendingPushOperation mPendingPushOperation;
74 80
75 /** 81 /**
76 * Utility that provides I/O operations for a Tag. Created on demand when Ta g is found. 82 * Utility that provides I/O operations for a Tag. Created on demand when Ta g is found.
77 * @see NfcTagHandler 83 * @see NfcTagHandler
78 */ 84 */
79 private NfcTagHandler mTagHandler; 85 private NfcTagHandler mTagHandler;
80 86
87 /**
88 * Client interface used to deliver NFCMessages for registered watch operati ons.
89 * @see #watch
90 */
91 private NfcClient mClient;
92
93 /**
94 * Watcher id that is incremented for each #watch call.
95 */
96 private int mWatcherId;
97
98 /**
99 * Map of watchId <-> NfcWatchOptions. All NfcWatchOptions are matched again st tag that is in
100 * proximnity, when match algorithm (@see #matchesWatchOptions) returns true , watcher with
Reilly Grant (use Gerrit) 2016/10/06 04:59:50 s/proximnity/proximity/
shalamov 2016/10/06 13:47:58 Done.
101 * corresponding ID would be notified using NfcClient interface.
102 * @see NfcClient#onWatch(int[] id, NfcMessage message)
103 */
104 private final SparseArray<NfcWatchOptions> mWatchers = new SparseArray<>();
105
81 public NfcImpl(Context context) { 106 public NfcImpl(Context context) {
82 int permission = 107 int permission =
83 context.checkPermission(Manifest.permission.NFC, Process.myPid() , Process.myUid()); 108 context.checkPermission(Manifest.permission.NFC, Process.myPid() , Process.myUid());
84 mHasPermission = permission == PackageManager.PERMISSION_GRANTED; 109 mHasPermission = permission == PackageManager.PERMISSION_GRANTED;
85 110
86 if (!mHasPermission || Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKA T) { 111 if (!mHasPermission || Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKA T) {
87 Log.w(TAG, "NFC operations are not permitted."); 112 Log.w(TAG, "NFC operations are not permitted.");
88 mNfcAdapter = null; 113 mNfcAdapter = null;
89 mNfcManager = null; 114 mNfcManager = null;
90 } else { 115 } else {
91 mNfcManager = (NfcManager) context.getSystemService(Context.NFC_SERV ICE); 116 mNfcManager = (NfcManager) context.getSystemService(Context.NFC_SERV ICE);
92 if (mNfcManager == null) { 117 if (mNfcManager == null) {
93 Log.w(TAG, "NFC is not supported."); 118 Log.w(TAG, "NFC is not supported.");
94 mNfcAdapter = null; 119 mNfcAdapter = null;
95 } else { 120 } else {
96 mNfcAdapter = mNfcManager.getDefaultAdapter(); 121 mNfcAdapter = mNfcManager.getDefaultAdapter();
97 } 122 }
98 } 123 }
99 } 124 }
100 125
101 /** 126 /**
102 * Sets Activity that is used to enable / disable NFC reader mode. When Acti vity is set, 127 * Sets Activity that is used to enable / disable NFC reader mode. When Acti vity is set,
103 * reader mode is disabled for old Activity and enabled for the new Activity . 128 * reader mode is disabled for old Activity and enabled for the new Activity .
104 */ 129 */
105 protected void setActivity(Activity activity) { 130 protected void setActivity(Activity activity) {
106 disableReaderMode(); 131 disableReaderMode();
107 mActivity = activity; 132 mActivity = activity;
108 enableReaderMode(); 133 enableReaderModeIfNeeded();
109 } 134 }
110 135
111 /** 136 /**
112 * Sets NfcClient. NfcClient interface is used to notify mojo NFC service cl ient when NFC 137 * Sets NfcClient. NfcClient interface is used to notify mojo NFC service cl ient when NFC
113 * device is in proximity and has NfcMessage that matches NfcWatchOptions cr iteria. 138 * device is in proximity and has NfcMessage that matches NfcWatchOptions cr iteria.
114 * @see Nfc#watch(NfcWatchOptions options, WatchResponse callback) 139 * @see Nfc#watch(NfcWatchOptions options, WatchResponse callback)
115 * 140 *
116 * @param client @see NfcClient 141 * @param client @see NfcClient
117 */ 142 */
118 @Override 143 @Override
119 public void setClient(NfcClient client) { 144 public void setClient(NfcClient client) {
120 // TODO(crbug.com/625589): Should be implemented when watch() is impleme nted. 145 mClient = client;
121 } 146 }
122 147
123 /** 148 /**
124 * Pushes NfcMessage to Tag or Peer, whenever NFC device is in proximity. At the moment, only 149 * Pushes NfcMessage to Tag or Peer, whenever NFC device is in proximity. At the moment, only
125 * passive NFC devices are supported (NfcPushTarget.TAG). 150 * passive NFC devices are supported (NfcPushTarget.TAG).
126 * 151 *
127 * @param message that should be pushed to NFC device. 152 * @param message that should be pushed to NFC device.
128 * @param options that contain information about timeout and target device t ype. 153 * @param options that contain information about timeout and target device t ype.
129 * @param callback that is used to notify when push operation is completed. 154 * @param callback that is used to notify when push operation is completed.
130 */ 155 */
131 @Override 156 @Override
132 public void push(NfcMessage message, NfcPushOptions options, PushResponse ca llback) { 157 public void push(NfcMessage message, NfcPushOptions options, PushResponse ca llback) {
133 if (!checkIfReady(callback)) return; 158 if (!checkIfReady(callback)) return;
134 159
160 if (!NfcMessageValidator.isValid(message)) {
161 callback.call(createError(NfcErrorType.INVALID_MESSAGE));
162 return;
163 }
164
135 if (options.target == NfcPushTarget.PEER) { 165 if (options.target == NfcPushTarget.PEER) {
136 callback.call(createError(NfcErrorType.NOT_SUPPORTED)); 166 callback.call(createError(NfcErrorType.NOT_SUPPORTED));
137 return; 167 return;
138 } 168 }
139 169
140 // If previous pending push operation is not completed, cancel it. 170 // If previous pending push operation is not completed, cancel it.
141 if (mPendingPushOperation != null) { 171 if (mPendingPushOperation != null) {
142 mPendingPushOperation.complete(createError(NfcErrorType.OPERATION_CA NCELLED)); 172 mPendingPushOperation.complete(createError(NfcErrorType.OPERATION_CA NCELLED));
143 } 173 }
144 174
145 mPendingPushOperation = new PendingPushOperation(message, options, callb ack); 175 mPendingPushOperation = new PendingPushOperation(message, options, callb ack);
146 enableReaderMode(); 176 enableReaderModeIfNeeded();
147 processPendingPushOperation(); 177 processPendingPushOperation();
148 } 178 }
149 179
150 /** 180 /**
151 * Cancels pending push operation. 181 * Cancels pending push operation.
152 * At the moment, only passive NFC devices are supported (NfcPushTarget.TAG) . 182 * At the moment, only passive NFC devices are supported (NfcPushTarget.TAG) .
153 * 183 *
154 * @param target @see NfcPushTarget 184 * @param target @see NfcPushTarget
155 * @param callback that is used to notify caller when cancelPush() is comple ted. 185 * @param callback that is used to notify caller when cancelPush() is comple ted.
156 */ 186 */
157 @Override 187 @Override
158 public void cancelPush(int target, CancelPushResponse callback) { 188 public void cancelPush(int target, CancelPushResponse callback) {
159 if (!checkIfReady(callback)) return; 189 if (!checkIfReady(callback)) return;
160 190
161 if (target == NfcPushTarget.PEER) { 191 if (target == NfcPushTarget.PEER) {
162 callback.call(createError(NfcErrorType.NOT_SUPPORTED)); 192 callback.call(createError(NfcErrorType.NOT_SUPPORTED));
163 return; 193 return;
164 } 194 }
165 195
166 if (mPendingPushOperation == null) { 196 if (mPendingPushOperation == null) {
167 callback.call(createError(NfcErrorType.NOT_FOUND)); 197 callback.call(createError(NfcErrorType.NOT_FOUND));
168 } else { 198 } else {
169 mPendingPushOperation.complete(createError(NfcErrorType.OPERATION_CA NCELLED)); 199 mPendingPushOperation.complete(createError(NfcErrorType.OPERATION_CA NCELLED));
170 mPendingPushOperation = null; 200 mPendingPushOperation = null;
171 callback.call(null); 201 callback.call(null);
172 disableReaderMode(); 202 disableReaderModeIfNeeded();
173 } 203 }
174 } 204 }
175 205
176 /** 206 /**
177 * Watch method allows to set filtering criteria for NfcMessages that are fo und when NFC device 207 * Watch method allows to set filtering criteria for NfcMessages that are fo und when NFC device
178 * is within proximity. On success, watch ID is returned to caller through W atchResponse 208 * is within proximity. On success, watch ID is returned to caller through W atchResponse
179 * callback. When NfcMessage that matches NfcWatchOptions is found, it is pa ssed to NfcClient 209 * callback. When NfcMessage that matches NfcWatchOptions is found, it is pa ssed to NfcClient
180 * interface together with corresponding watch ID. 210 * interface together with corresponding watch ID.
181 * @see NfcClient#onWatch(int[] id, NfcMessage message) 211 * @see NfcClient#onWatch(int[] id, NfcMessage message)
182 * 212 *
183 * @param options used to filter NfcMessages, @see NfcWatchOptions. 213 * @param options used to filter NfcMessages, @see NfcWatchOptions.
184 * @param callback that is used to notify caller when watch() is completed a nd return watch ID. 214 * @param callback that is used to notify caller when watch() is completed a nd return watch ID.
185 */ 215 */
186 @Override 216 @Override
187 public void watch(NfcWatchOptions options, WatchResponse callback) { 217 public void watch(NfcWatchOptions options, WatchResponse callback) {
188 if (!checkIfReady(callback)) return; 218 if (!checkIfReady(callback)) return;
189 // TODO(crbug.com/625589): Not implemented. 219 int watcherId = ++mWatcherId;
190 callback.call(0, createError(NfcErrorType.NOT_SUPPORTED)); 220 mWatchers.put(watcherId, options);
221 callback.call(watcherId, null);
222 enableReaderModeIfNeeded();
223 processPendingWatchOperations();
191 } 224 }
192 225
193 /** 226 /**
194 * Cancels NFC watch operation. 227 * Cancels NFC watch operation.
195 * 228 *
196 * @param id of watch operation. 229 * @param id of watch operation.
197 * @param callback that is used to notify caller when cancelWatch() is compl eted. 230 * @param callback that is used to notify caller when cancelWatch() is compl eted.
198 */ 231 */
199 @Override 232 @Override
200 public void cancelWatch(int id, CancelWatchResponse callback) { 233 public void cancelWatch(int id, CancelWatchResponse callback) {
201 if (!checkIfReady(callback)) return; 234 if (!checkIfReady(callback)) return;
202 // TODO(crbug.com/625589): Not implemented. 235
203 callback.call(createError(NfcErrorType.NOT_SUPPORTED)); 236 if (mWatchers.indexOfKey(id) < 0) {
237 callback.call(createError(NfcErrorType.NOT_FOUND));
238 } else {
239 mWatchers.remove(id);
240 callback.call(null);
241 disableReaderModeIfNeeded();
242 }
204 } 243 }
205 244
206 /** 245 /**
207 * Cancels all NFC watch operations. 246 * Cancels all NFC watch operations.
208 * 247 *
209 * @param callback that is used to notify caller when cancelAllWatches() is completed. 248 * @param callback that is used to notify caller when cancelAllWatches() is completed.
210 */ 249 */
211 @Override 250 @Override
212 public void cancelAllWatches(CancelAllWatchesResponse callback) { 251 public void cancelAllWatches(CancelAllWatchesResponse callback) {
213 if (!checkIfReady(callback)) return; 252 if (!checkIfReady(callback)) return;
214 // TODO(crbug.com/625589): Not implemented. 253
215 callback.call(createError(NfcErrorType.NOT_SUPPORTED)); 254 if (mWatchers.size() == 0) {
255 callback.call(createError(NfcErrorType.NOT_FOUND));
256 } else {
257 mWatchers.clear();
258 callback.call(null);
259 disableReaderModeIfNeeded();
260 }
216 } 261 }
217 262
218 /** 263 /**
219 * Suspends all pending operations. Should be called when web page visibilit y is lost. 264 * Suspends all pending operations. Should be called when web page visibilit y is lost.
220 */ 265 */
221 @Override 266 @Override
222 public void suspendNfcOperations() { 267 public void suspendNfcOperations() {
223 disableReaderMode(); 268 disableReaderMode();
224 } 269 }
225 270
226 /** 271 /**
227 * Resumes all pending watch / push operations. Should be called when web pa ge becomes visible. 272 * Resumes all pending watch / push operations. Should be called when web pa ge becomes visible.
228 */ 273 */
229 @Override 274 @Override
230 public void resumeNfcOperations() { 275 public void resumeNfcOperations() {
231 enableReaderMode(); 276 enableReaderModeIfNeeded();
232 } 277 }
233 278
234 @Override 279 @Override
235 public void close() { 280 public void close() {
236 disableReaderMode(); 281 disableReaderMode();
237 } 282 }
238 283
239 @Override 284 @Override
240 public void onConnectionError(MojoException e) { 285 public void onConnectionError(MojoException e) {
241 close(); 286 close();
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
336 @Override 381 @Override
337 public void onTagDiscovered(Tag tag) { 382 public void onTagDiscovered(Tag tag) {
338 mNfcImpl.onTagDiscovered(tag); 383 mNfcImpl.onTagDiscovered(tag);
339 } 384 }
340 } 385 }
341 386
342 /** 387 /**
343 * Enables reader mode, allowing NFC device to read / write NFC tags. 388 * Enables reader mode, allowing NFC device to read / write NFC tags.
344 * @see android.nfc.NfcAdapter#enableReaderMode 389 * @see android.nfc.NfcAdapter#enableReaderMode
345 */ 390 */
346 private void enableReaderMode() { 391 private void enableReaderModeIfNeeded() {
347 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return; 392 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return;
348 393
349 if (mReaderCallbackHandler != null || mActivity == null || mNfcAdapter = = null) return; 394 if (mReaderCallbackHandler != null || mActivity == null || mNfcAdapter = = null) return;
350 395
351 // TODO(crbug.com/625589): Check if there are active watch operations. 396 // Do not enable reader mode, if there are no active push / watch operat ions.
352 if (mPendingPushOperation == null) return; 397 if (mPendingPushOperation == null && mWatchers.size() == 0) return;
353 398
354 mReaderCallbackHandler = new ReaderCallbackHandler(this); 399 mReaderCallbackHandler = new ReaderCallbackHandler(this);
355 mNfcAdapter.enableReaderMode(mActivity, mReaderCallbackHandler, 400 mNfcAdapter.enableReaderMode(mActivity, mReaderCallbackHandler,
356 NfcAdapter.FLAG_READER_NFC_A | NfcAdapter.FLAG_READER_NFC_B 401 NfcAdapter.FLAG_READER_NFC_A | NfcAdapter.FLAG_READER_NFC_B
357 | NfcAdapter.FLAG_READER_NFC_F | NfcAdapter.FLAG_READER_ NFC_V, 402 | NfcAdapter.FLAG_READER_NFC_F | NfcAdapter.FLAG_READER_ NFC_V,
358 null); 403 null);
359 } 404 }
360 405
361 /** 406 /**
362 * Disables reader mode. 407 * Disables reader mode.
363 * @see android.nfc.NfcAdapter#disableReaderMode 408 * @see android.nfc.NfcAdapter#disableReaderMode
364 */ 409 */
365 @TargetApi(Build.VERSION_CODES.KITKAT) 410 @TargetApi(Build.VERSION_CODES.KITKAT)
366 private void disableReaderMode() { 411 private void disableReaderMode() {
367 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return; 412 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return;
368 413
369 // There is no API that could query whether reader mode is enabled for a dapter. 414 // There is no API that could query whether reader mode is enabled for a dapter.
370 // If mReaderCallbackHandler is null, reader mode is not enabled. 415 // If mReaderCallbackHandler is null, reader mode is not enabled.
371 if (mReaderCallbackHandler == null) return; 416 if (mReaderCallbackHandler == null) return;
372 417
373 mReaderCallbackHandler = null; 418 mReaderCallbackHandler = null;
374 if (mActivity != null && mNfcAdapter != null && !mActivity.isDestroyed() ) { 419 if (mActivity != null && mNfcAdapter != null && !mActivity.isDestroyed() ) {
375 mNfcAdapter.disableReaderMode(mActivity); 420 mNfcAdapter.disableReaderMode(mActivity);
376 } 421 }
377 } 422 }
378 423
379 /** 424 /**
425 * Checks if there are pending push / watch operations and disables readre m ode
426 * whenever necessary.
427 */
428 private void disableReaderModeIfNeeded() {
429 if (mPendingPushOperation == null && mWatchers.size() == 0) {
430 disableReaderMode();
431 }
432 }
433
434 /**
380 * Completes pending push operation. On error, invalidates #mTagHandler. 435 * Completes pending push operation. On error, invalidates #mTagHandler.
381 */ 436 */
382 private void pendingPushOperationCompleted(NfcError error) { 437 private void pendingPushOperationCompleted(NfcError error) {
383 if (mPendingPushOperation != null) { 438 if (mPendingPushOperation != null) {
384 mPendingPushOperation.complete(error); 439 mPendingPushOperation.complete(error);
385 mPendingPushOperation = null; 440 mPendingPushOperation = null;
386 441 disableReaderModeIfNeeded();
387 // TODO(crbug.com/625589): When nfc.watch is implemented, disable re ader mode
388 // only when there are no active watch operations.
389 disableReaderMode();
390 } 442 }
391 443
392 if (error != null) mTagHandler = null; 444 if (error != null) mTagHandler = null;
393 } 445 }
394 446
395 /** 447 /**
396 * Checks whether there is a #mPendingPushOperation and writes data to NFC t ag. In case of 448 * Checks whether there is a #mPendingPushOperation and writes data to NFC t ag. In case of
397 * exception calls pendingPushOperationCompleted() with appropriate error ob ject. 449 * exception calls pendingPushOperationCompleted() with appropriate error ob ject.
398 */ 450 */
399 private void processPendingPushOperation() { 451 private void processPendingPushOperation() {
400 if (mTagHandler == null || mPendingPushOperation == null) return; 452 if (mTagHandler == null || mPendingPushOperation == null) return;
401 453
402 if (mTagHandler.isTagOutOfRange()) { 454 if (mTagHandler.isTagOutOfRange()) {
403 mTagHandler = null; 455 mTagHandler = null;
404 return; 456 return;
405 } 457 }
406 458
407 try { 459 try {
408 mTagHandler.connect(); 460 mTagHandler.connect();
409 mTagHandler.write(NfcTypeConverter.toNdefMessage(mPendingPushOperati on.nfcMessage)); 461 mTagHandler.write(NfcTypeConverter.toNdefMessage(mPendingPushOperati on.nfcMessage));
410 pendingPushOperationCompleted(null); 462 pendingPushOperationCompleted(null);
411 mTagHandler.close();
412 } catch (InvalidNfcMessageException e) { 463 } catch (InvalidNfcMessageException e) {
413 Log.w(TAG, "Cannot write data to NFC tag. Invalid NfcMessage."); 464 Log.w(TAG, "Cannot write data to NFC tag. Invalid NfcMessage.");
414 pendingPushOperationCompleted(createError(NfcErrorType.INVALID_MESSA GE)); 465 pendingPushOperationCompleted(createError(NfcErrorType.INVALID_MESSA GE));
415 } catch (TagLostException e) { 466 } catch (TagLostException e) {
416 Log.w(TAG, "Cannot write data to NFC tag. Tag is lost."); 467 Log.w(TAG, "Cannot write data to NFC tag. Tag is lost.");
417 pendingPushOperationCompleted(createError(NfcErrorType.IO_ERROR)); 468 pendingPushOperationCompleted(createError(NfcErrorType.IO_ERROR));
418 } catch (FormatException | IOException e) { 469 } catch (FormatException | IOException e) {
419 Log.w(TAG, "Cannot write data to NFC tag. IO_ERROR."); 470 Log.w(TAG, "Cannot write data to NFC tag. IO_ERROR.");
420 pendingPushOperationCompleted(createError(NfcErrorType.IO_ERROR)); 471 pendingPushOperationCompleted(createError(NfcErrorType.IO_ERROR));
421 } 472 }
422 } 473 }
423 474
424 /** 475 /**
476 * Reads NfcMessage from a tag and forwards message to matching method.
477 */
478 private void processPendingWatchOperations() {
479 if (mTagHandler == null || mClient == null || mWatchers.size() == 0) ret urn;
480
481 // Skip reading if there is a pending push operation and ignoreRead flag is set.
482 if (mPendingPushOperation != null && mPendingPushOperation.nfcPushOption s.ignoreRead) {
483 return;
484 }
485
486 if (mTagHandler.isTagOutOfRange()) {
487 mTagHandler = null;
488 return;
489 }
490
491 NdefMessage message = null;
492
493 try {
494 mTagHandler.connect();
495 message = mTagHandler.read();
496 if (message.getByteArrayLength() > NfcMessage.MAX_SIZE) {
497 Log.w(TAG, "Cannot read data from NFC tag. NfcMessage exceeds al lowed size.");
498 return;
499 }
500 } catch (TagLostException e) {
501 Log.w(TAG, "Cannot read data from NFC tag. Tag is lost.");
502 } catch (FormatException | IOException e) {
503 Log.w(TAG, "Cannot read data from NFC tag. IO_ERROR.");
504 }
505
506 if (message != null) notifyMatchingWatchers(message);
507 }
508
509 /**
510 * Iterates through active watchers and if any of those match NfcWatchOption s criteria,
511 * delivers NfcMessage to the client.
512 */
513 private void notifyMatchingWatchers(NdefMessage message) {
514 try {
515 NfcMessage nfcMessage = NfcTypeConverter.toNfcMessage(message);
516 List<Integer> watchIds = new ArrayList<Integer>();
517 for (int i = 0; i < mWatchers.size(); i++) {
518 NfcWatchOptions options = mWatchers.valueAt(i);
519 if (matchesWatchOptions(nfcMessage, options)) watchIds.add(mWatc hers.keyAt(i));
520 }
521
522 if (watchIds.size() != 0) {
523 int[] ids = new int[watchIds.size()];
524 for (int i = 0; i < watchIds.size(); ++i) {
525 ids[i] = watchIds.get(i).intValue();
526 }
527 mClient.onWatch(ids, nfcMessage);
528 }
529 } catch (UnsupportedEncodingException e) {
530 Log.w(TAG, "Cannot convert NdefMessage to NfcMessage.");
531 }
532 }
533
534 /**
535 * Implements matching algorithm.
536 */
537 private boolean matchesWatchOptions(NfcMessage message, NfcWatchOptions opti ons) {
538 // Valid WebNFC message must have non-empty url.
539 if (options.mode == NfcWatchMode.WEBNFC_ONLY
540 && (message.url == null || message.url.isEmpty())) {
541 return false;
542 }
543
544 // Filter by NfcMessage.url
545 if (options.url != null && !options.url.isEmpty() && !options.url.equals (message.url)) {
546 return false;
547 }
548
549 // Matches any record / media type.
550 if ((options.mediaType == null || options.mediaType.isEmpty())
551 && options.recordFilter == null) {
552 return true;
553 }
554
555 // Filter by mediaType and recordType
556 for (int i = 0; i < message.data.length; i++) {
557 boolean matchedMediaType;
558 boolean matchedRecordType;
559
560 if (options.mediaType == null || options.mediaType.isEmpty()) {
561 // If media type for the watch options is empty, match all media types.
562 matchedMediaType = true;
563 } else {
564 matchedMediaType = options.mediaType.equals(message.data[i].medi aType);
565 }
566
567 if (options.recordFilter == null) {
568 // If record type filter for the watch options is null, match al l record types.
569 matchedRecordType = true;
570 } else {
571 matchedRecordType = options.recordFilter.recordType == message.d ata[i].recordType;
572 }
573
574 if (matchedMediaType && matchedRecordType) return true;
575 }
576
577 return false;
578 }
579
580 /**
425 * Called by ReaderCallbackHandler when NFC tag is in proximity. 581 * Called by ReaderCallbackHandler when NFC tag is in proximity.
426 */ 582 */
427 public void onTagDiscovered(Tag tag) { 583 public void onTagDiscovered(Tag tag) {
428 mTagHandler = NfcTagHandler.create(tag); 584 processPendingOperations(NfcTagHandler.create(tag));
585 }
586
587 /**
588 * Processes pending operation when NFC tag is in proximity.
589 */
590 protected void processPendingOperations(NfcTagHandler tagHandler) {
591 mTagHandler = tagHandler;
592 processPendingWatchOperations();
429 processPendingPushOperation(); 593 processPendingPushOperation();
594 if (mTagHandler != null && mTagHandler.isConnected()) {
595 try {
596 mTagHandler.close();
597 } catch (IOException e) {
598 Log.w(TAG, "Cannot close NFC tag connection.");
599 }
600 }
430 } 601 }
431 } 602 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698