139f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenen/* 239f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenen * Copyright (C) 2010 The Android Open Source Project 339f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenen * 439f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenen * Licensed under the Apache License, Version 2.0 (the "License"); 539f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenen * you may not use this file except in compliance with the License. 639f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenen * You may obtain a copy of the License at 739f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenen * 839f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenen * http://www.apache.org/licenses/LICENSE-2.0 939f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenen * 1039f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenen * Unless required by applicable law or agreed to in writing, software 1139f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenen * distributed under the License is distributed on an "AS IS" BASIS, 1239f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1339f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenen * See the License for the specific language governing permissions and 1439f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenen * limitations under the License. 1539f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenen */ 1639f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenen 174e21e1d21a877cce4db5ec8c5786604cc10f2d7eJeff Hamiltonpackage android.nfc.tech; 1839f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenen 1939f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenenimport android.nfc.ErrorCodes; 2039f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenenimport android.nfc.FormatException; 214e21e1d21a877cce4db5ec8c5786604cc10f2d7eJeff Hamiltonimport android.nfc.INfcTag; 2239f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenenimport android.nfc.NdefMessage; 2339f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenenimport android.nfc.Tag; 2474fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pellyimport android.nfc.TagLostException; 2539f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenenimport android.os.RemoteException; 263dd6c458530476eccb33bc05c9c9cd83823bcf8dNick Pellyimport android.util.Log; 2739f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenen 2839f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenenimport java.io.IOException; 2939f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenen 3039f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenen/** 3174fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * Provide access to NDEF format operations on a {@link Tag}. 3239f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenen * 3374fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * <p>Acquire a {@link NdefFormatable} object using {@link #get}. 3474fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * 3574fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * <p>Android devices with NFC must only enumerate and implement this 3674fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * class for tags for which it can format to NDEF. 3774fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * 3874fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * <p>Unfortunately the procedures to convert unformated tags to NDEF formatted 3974fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * tags are not specified by NFC Forum, and are not generally well-known. So 4074fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * there is no mandatory set of tags for which all Android devices with NFC 4174fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * must support {@link NdefFormatable}. 4239f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenen * 4339cf3a445e507f219ecc8a476f6038f095d9d520Nick Pelly * <p class="note"><strong>Note:</strong> Methods that perform I/O operations 4439cf3a445e507f219ecc8a476f6038f095d9d520Nick Pelly * require the {@link android.Manifest.permission#NFC} permission. 4539f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenen */ 4639f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenenpublic final class NdefFormatable extends BasicTagTechnology { 473dd6c458530476eccb33bc05c9c9cd83823bcf8dNick Pelly private static final String TAG = "NFC"; 483dd6c458530476eccb33bc05c9c9cd83823bcf8dNick Pelly 4939f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenen /** 5074fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * Get an instance of {@link NdefFormatable} for the given tag. 5174fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * <p>Does not cause any RF activity and does not block. 5274fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * <p>Returns null if {@link NdefFormatable} was not enumerated in {@link Tag#getTechList}. 5374fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * This indicates the tag is not NDEF formatable by this Android device. 544e21e1d21a877cce4db5ec8c5786604cc10f2d7eJeff Hamilton * 5574fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * @param tag an NDEF formatable tag 5674fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * @return NDEF formatable object 574e21e1d21a877cce4db5ec8c5786604cc10f2d7eJeff Hamilton */ 584e21e1d21a877cce4db5ec8c5786604cc10f2d7eJeff Hamilton public static NdefFormatable get(Tag tag) { 594e21e1d21a877cce4db5ec8c5786604cc10f2d7eJeff Hamilton if (!tag.hasTech(TagTechnology.NDEF_FORMATABLE)) return null; 604e21e1d21a877cce4db5ec8c5786604cc10f2d7eJeff Hamilton try { 614e21e1d21a877cce4db5ec8c5786604cc10f2d7eJeff Hamilton return new NdefFormatable(tag); 624e21e1d21a877cce4db5ec8c5786604cc10f2d7eJeff Hamilton } catch (RemoteException e) { 634e21e1d21a877cce4db5ec8c5786604cc10f2d7eJeff Hamilton return null; 644e21e1d21a877cce4db5ec8c5786604cc10f2d7eJeff Hamilton } 654e21e1d21a877cce4db5ec8c5786604cc10f2d7eJeff Hamilton } 664e21e1d21a877cce4db5ec8c5786604cc10f2d7eJeff Hamilton 674e21e1d21a877cce4db5ec8c5786604cc10f2d7eJeff Hamilton /** 6839f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenen * Internal constructor, to be used by NfcAdapter 6939f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenen * @hide 7039f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenen */ 714e21e1d21a877cce4db5ec8c5786604cc10f2d7eJeff Hamilton public NdefFormatable(Tag tag) throws RemoteException { 724e21e1d21a877cce4db5ec8c5786604cc10f2d7eJeff Hamilton super(tag, TagTechnology.NDEF_FORMATABLE); 7339f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenen } 7439f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenen 7539f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenen /** 7674fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * Format a tag as NDEF, and write a {@link NdefMessage}. 7774fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * 7874fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * <p>This is a multi-step process, an IOException is thrown 7974fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * if any one step fails. 8074fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * <p>The card is left in a read-write state after this operation. 8174fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * 8274fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * <p>This is an I/O operation and will block until complete. It must 8374fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * not be called from the main application thread. A blocked call will be canceled with 8474fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * {@link IOException} if {@link #close} is called from another thread. 8574fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * 8639cf3a445e507f219ecc8a476f6038f095d9d520Nick Pelly * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. 8739cf3a445e507f219ecc8a476f6038f095d9d520Nick Pelly * 8839cf3a445e507f219ecc8a476f6038f095d9d520Nick Pelly * @param firstMessage the NDEF message to write after formatting, can be null 8974fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * @throws TagLostException if the tag leaves the field 9074fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * @throws IOException if there is an I/O failure, or the operation is canceled 9174fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * @throws FormatException if the NDEF Message to write is malformed 9239f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenen */ 9346797ac098e90cbef5c266b75fb37fc06e9acc80Nick Pelly public void format(NdefMessage firstMessage) throws IOException, FormatException { 9446797ac098e90cbef5c266b75fb37fc06e9acc80Nick Pelly format(firstMessage, false); 95f003e26df96067b4b136f0859012cb7ec3ed930fNick Pelly } 96f003e26df96067b4b136f0859012cb7ec3ed930fNick Pelly 97f003e26df96067b4b136f0859012cb7ec3ed930fNick Pelly /** 9874fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * Formats a tag as NDEF, write a {@link NdefMessage}, and make read-only. 9974fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * 10074fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * <p>This is a multi-step process, an IOException is thrown 10174fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * if any one step fails. 10274fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * <p>The card is left in a read-only state if this method returns successfully. 10374fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * 10474fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * <p>This is an I/O operation and will block until complete. It must 10574fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * not be called from the main application thread. A blocked call will be canceled with 10674fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * {@link IOException} if {@link #close} is called from another thread. 10774fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * 10839cf3a445e507f219ecc8a476f6038f095d9d520Nick Pelly * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. 10939cf3a445e507f219ecc8a476f6038f095d9d520Nick Pelly * 11046797ac098e90cbef5c266b75fb37fc06e9acc80Nick Pelly * @param firstMessage the NDEF message to write after formatting 11174fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * @throws TagLostException if the tag leaves the field 11274fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * @throws IOException if there is an I/O failure, or the operation is canceled 11374fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * @throws FormatException if the NDEF Message to write is malformed 114f003e26df96067b4b136f0859012cb7ec3ed930fNick Pelly */ 11546797ac098e90cbef5c266b75fb37fc06e9acc80Nick Pelly public void formatReadOnly(NdefMessage firstMessage) throws IOException, FormatException { 11646797ac098e90cbef5c266b75fb37fc06e9acc80Nick Pelly format(firstMessage, true); 117f003e26df96067b4b136f0859012cb7ec3ed930fNick Pelly } 118f003e26df96067b4b136f0859012cb7ec3ed930fNick Pelly 119f003e26df96067b4b136f0859012cb7ec3ed930fNick Pelly /*package*/ void format(NdefMessage firstMessage, boolean makeReadOnly) throws IOException, 120f003e26df96067b4b136f0859012cb7ec3ed930fNick Pelly FormatException { 1214049f9d00a86f848d42d2429068496b31a6795adMartijn Coenen checkConnected(); 1224049f9d00a86f848d42d2429068496b31a6795adMartijn Coenen 1235289b91c885158094988a9a7b51b3139565eb639Martijn Coenen try { 1245289b91c885158094988a9a7b51b3139565eb639Martijn Coenen int serviceHandle = mTag.getServiceHandle(); 1254e21e1d21a877cce4db5ec8c5786604cc10f2d7eJeff Hamilton INfcTag tagService = mTag.getTagService(); 1264e21e1d21a877cce4db5ec8c5786604cc10f2d7eJeff Hamilton int errorCode = tagService.formatNdef(serviceHandle, MifareClassic.KEY_DEFAULT); 1275289b91c885158094988a9a7b51b3139565eb639Martijn Coenen switch (errorCode) { 1285289b91c885158094988a9a7b51b3139565eb639Martijn Coenen case ErrorCodes.SUCCESS: 1295289b91c885158094988a9a7b51b3139565eb639Martijn Coenen break; 1305289b91c885158094988a9a7b51b3139565eb639Martijn Coenen case ErrorCodes.ERROR_IO: 1315289b91c885158094988a9a7b51b3139565eb639Martijn Coenen throw new IOException(); 1325289b91c885158094988a9a7b51b3139565eb639Martijn Coenen case ErrorCodes.ERROR_INVALID_PARAM: 1335289b91c885158094988a9a7b51b3139565eb639Martijn Coenen throw new FormatException(); 1345289b91c885158094988a9a7b51b3139565eb639Martijn Coenen default: 1355289b91c885158094988a9a7b51b3139565eb639Martijn Coenen // Should not happen 1365289b91c885158094988a9a7b51b3139565eb639Martijn Coenen throw new IOException(); 1375289b91c885158094988a9a7b51b3139565eb639Martijn Coenen } 138e3f6336bcffc250da90ec864bccfa73ad1d016b9Martijn Coenen // Now check and see if the format worked 1392976da0305367ac051d0fcae160bfdb0497b2750Martijn Coenen if (!tagService.isNdef(serviceHandle)) { 1402976da0305367ac051d0fcae160bfdb0497b2750Martijn Coenen throw new IOException(); 1412976da0305367ac051d0fcae160bfdb0497b2750Martijn Coenen } 1422976da0305367ac051d0fcae160bfdb0497b2750Martijn Coenen 1432976da0305367ac051d0fcae160bfdb0497b2750Martijn Coenen // Write a message, if one was provided 1442976da0305367ac051d0fcae160bfdb0497b2750Martijn Coenen if (firstMessage != null) { 1454e21e1d21a877cce4db5ec8c5786604cc10f2d7eJeff Hamilton errorCode = tagService.ndefWrite(serviceHandle, firstMessage); 146e3f6336bcffc250da90ec864bccfa73ad1d016b9Martijn Coenen switch (errorCode) { 147e3f6336bcffc250da90ec864bccfa73ad1d016b9Martijn Coenen case ErrorCodes.SUCCESS: 148e3f6336bcffc250da90ec864bccfa73ad1d016b9Martijn Coenen break; 149e3f6336bcffc250da90ec864bccfa73ad1d016b9Martijn Coenen case ErrorCodes.ERROR_IO: 150e3f6336bcffc250da90ec864bccfa73ad1d016b9Martijn Coenen throw new IOException(); 151e3f6336bcffc250da90ec864bccfa73ad1d016b9Martijn Coenen case ErrorCodes.ERROR_INVALID_PARAM: 152e3f6336bcffc250da90ec864bccfa73ad1d016b9Martijn Coenen throw new FormatException(); 153e3f6336bcffc250da90ec864bccfa73ad1d016b9Martijn Coenen default: 154e3f6336bcffc250da90ec864bccfa73ad1d016b9Martijn Coenen // Should not happen 155e3f6336bcffc250da90ec864bccfa73ad1d016b9Martijn Coenen throw new IOException(); 156e3f6336bcffc250da90ec864bccfa73ad1d016b9Martijn Coenen } 1575289b91c885158094988a9a7b51b3139565eb639Martijn Coenen } 1582976da0305367ac051d0fcae160bfdb0497b2750Martijn Coenen 159f003e26df96067b4b136f0859012cb7ec3ed930fNick Pelly // optionally make read-only 160f003e26df96067b4b136f0859012cb7ec3ed930fNick Pelly if (makeReadOnly) { 161f003e26df96067b4b136f0859012cb7ec3ed930fNick Pelly errorCode = tagService.ndefMakeReadOnly(serviceHandle); 162f003e26df96067b4b136f0859012cb7ec3ed930fNick Pelly switch (errorCode) { 163f003e26df96067b4b136f0859012cb7ec3ed930fNick Pelly case ErrorCodes.SUCCESS: 164f003e26df96067b4b136f0859012cb7ec3ed930fNick Pelly break; 165f003e26df96067b4b136f0859012cb7ec3ed930fNick Pelly case ErrorCodes.ERROR_IO: 166f003e26df96067b4b136f0859012cb7ec3ed930fNick Pelly throw new IOException(); 167f003e26df96067b4b136f0859012cb7ec3ed930fNick Pelly case ErrorCodes.ERROR_INVALID_PARAM: 168f003e26df96067b4b136f0859012cb7ec3ed930fNick Pelly throw new IOException(); 169f003e26df96067b4b136f0859012cb7ec3ed930fNick Pelly default: 170f003e26df96067b4b136f0859012cb7ec3ed930fNick Pelly // Should not happen 171f003e26df96067b4b136f0859012cb7ec3ed930fNick Pelly throw new IOException(); 172f003e26df96067b4b136f0859012cb7ec3ed930fNick Pelly } 173f003e26df96067b4b136f0859012cb7ec3ed930fNick Pelly } 1745289b91c885158094988a9a7b51b3139565eb639Martijn Coenen } catch (RemoteException e) { 1753dd6c458530476eccb33bc05c9c9cd83823bcf8dNick Pelly Log.e(TAG, "NFC service dead", e); 1765289b91c885158094988a9a7b51b3139565eb639Martijn Coenen } 17739f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenen } 17839f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenen} 179