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.NfcAdapter; 2439f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenenimport android.nfc.Tag; 2574fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pellyimport android.nfc.TagLostException; 2639f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenenimport android.os.RemoteException; 273dd6c458530476eccb33bc05c9c9cd83823bcf8dNick Pellyimport android.util.Log; 2839f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenen 2939f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenenimport java.io.IOException; 3039f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenen 3139f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenen/** 3274fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * Provide access to NDEF format operations on a {@link Tag}. 3339f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenen * 3474fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * <p>Acquire a {@link NdefFormatable} object using {@link #get}. 3574fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * 3674fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * <p>Android devices with NFC must only enumerate and implement this 3774fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * class for tags for which it can format to NDEF. 3874fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * 3974fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * <p>Unfortunately the procedures to convert unformated tags to NDEF formatted 4074fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * tags are not specified by NFC Forum, and are not generally well-known. So 4174fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * there is no mandatory set of tags for which all Android devices with NFC 4274fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * must support {@link NdefFormatable}. 4339f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenen * 4439cf3a445e507f219ecc8a476f6038f095d9d520Nick Pelly * <p class="note"><strong>Note:</strong> Methods that perform I/O operations 4539cf3a445e507f219ecc8a476f6038f095d9d520Nick Pelly * require the {@link android.Manifest.permission#NFC} permission. 4639f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenen */ 4739f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenenpublic final class NdefFormatable extends BasicTagTechnology { 483dd6c458530476eccb33bc05c9c9cd83823bcf8dNick Pelly private static final String TAG = "NFC"; 493dd6c458530476eccb33bc05c9c9cd83823bcf8dNick Pelly 5039f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenen /** 5174fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * Get an instance of {@link NdefFormatable} for the given tag. 5274fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * <p>Does not cause any RF activity and does not block. 5374fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * <p>Returns null if {@link NdefFormatable} was not enumerated in {@link Tag#getTechList}. 5474fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * This indicates the tag is not NDEF formatable by this Android device. 554e21e1d21a877cce4db5ec8c5786604cc10f2d7eJeff Hamilton * 5674fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * @param tag an NDEF formatable tag 5774fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * @return NDEF formatable object 584e21e1d21a877cce4db5ec8c5786604cc10f2d7eJeff Hamilton */ 594e21e1d21a877cce4db5ec8c5786604cc10f2d7eJeff Hamilton public static NdefFormatable get(Tag tag) { 604e21e1d21a877cce4db5ec8c5786604cc10f2d7eJeff Hamilton if (!tag.hasTech(TagTechnology.NDEF_FORMATABLE)) return null; 614e21e1d21a877cce4db5ec8c5786604cc10f2d7eJeff Hamilton try { 624e21e1d21a877cce4db5ec8c5786604cc10f2d7eJeff Hamilton return new NdefFormatable(tag); 634e21e1d21a877cce4db5ec8c5786604cc10f2d7eJeff Hamilton } catch (RemoteException e) { 644e21e1d21a877cce4db5ec8c5786604cc10f2d7eJeff Hamilton return null; 654e21e1d21a877cce4db5ec8c5786604cc10f2d7eJeff Hamilton } 664e21e1d21a877cce4db5ec8c5786604cc10f2d7eJeff Hamilton } 674e21e1d21a877cce4db5ec8c5786604cc10f2d7eJeff Hamilton 684e21e1d21a877cce4db5ec8c5786604cc10f2d7eJeff Hamilton /** 6939f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenen * Internal constructor, to be used by NfcAdapter 7039f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenen * @hide 7139f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenen */ 724e21e1d21a877cce4db5ec8c5786604cc10f2d7eJeff Hamilton public NdefFormatable(Tag tag) throws RemoteException { 734e21e1d21a877cce4db5ec8c5786604cc10f2d7eJeff Hamilton super(tag, TagTechnology.NDEF_FORMATABLE); 7439f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenen } 7539f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenen 7639f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenen /** 7774fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * Format a tag as NDEF, and write a {@link NdefMessage}. 7874fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * 7974fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * <p>This is a multi-step process, an IOException is thrown 8074fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * if any one step fails. 8174fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * <p>The card is left in a read-write state after this operation. 8274fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * 8374fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * <p>This is an I/O operation and will block until complete. It must 8474fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * not be called from the main application thread. A blocked call will be canceled with 8574fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * {@link IOException} if {@link #close} is called from another thread. 8674fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * 8739cf3a445e507f219ecc8a476f6038f095d9d520Nick Pelly * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. 8839cf3a445e507f219ecc8a476f6038f095d9d520Nick Pelly * 8939cf3a445e507f219ecc8a476f6038f095d9d520Nick Pelly * @param firstMessage the NDEF message to write after formatting, can be null 9074fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * @throws TagLostException if the tag leaves the field 9174fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * @throws IOException if there is an I/O failure, or the operation is canceled 9274fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * @throws FormatException if the NDEF Message to write is malformed 9339f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenen */ 9446797ac098e90cbef5c266b75fb37fc06e9acc80Nick Pelly public void format(NdefMessage firstMessage) throws IOException, FormatException { 9546797ac098e90cbef5c266b75fb37fc06e9acc80Nick Pelly format(firstMessage, false); 96f003e26df96067b4b136f0859012cb7ec3ed930fNick Pelly } 97f003e26df96067b4b136f0859012cb7ec3ed930fNick Pelly 98f003e26df96067b4b136f0859012cb7ec3ed930fNick Pelly /** 9974fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * Formats a tag as NDEF, write a {@link NdefMessage}, and make read-only. 10074fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * 10174fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * <p>This is a multi-step process, an IOException is thrown 10274fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * if any one step fails. 10374fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * <p>The card is left in a read-only state if this method returns successfully. 10474fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * 10574fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * <p>This is an I/O operation and will block until complete. It must 10674fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * not be called from the main application thread. A blocked call will be canceled with 10774fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * {@link IOException} if {@link #close} is called from another thread. 10874fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * 10939cf3a445e507f219ecc8a476f6038f095d9d520Nick Pelly * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. 11039cf3a445e507f219ecc8a476f6038f095d9d520Nick Pelly * 11146797ac098e90cbef5c266b75fb37fc06e9acc80Nick Pelly * @param firstMessage the NDEF message to write after formatting 11274fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * @throws TagLostException if the tag leaves the field 11374fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * @throws IOException if there is an I/O failure, or the operation is canceled 11474fe6c6b245ebe7d3b3d96962c32980d88dca4f5Nick Pelly * @throws FormatException if the NDEF Message to write is malformed 115f003e26df96067b4b136f0859012cb7ec3ed930fNick Pelly */ 11646797ac098e90cbef5c266b75fb37fc06e9acc80Nick Pelly public void formatReadOnly(NdefMessage firstMessage) throws IOException, FormatException { 11746797ac098e90cbef5c266b75fb37fc06e9acc80Nick Pelly format(firstMessage, true); 118f003e26df96067b4b136f0859012cb7ec3ed930fNick Pelly } 119f003e26df96067b4b136f0859012cb7ec3ed930fNick Pelly 120f003e26df96067b4b136f0859012cb7ec3ed930fNick Pelly /*package*/ void format(NdefMessage firstMessage, boolean makeReadOnly) throws IOException, 121f003e26df96067b4b136f0859012cb7ec3ed930fNick Pelly FormatException { 1224049f9d00a86f848d42d2429068496b31a6795adMartijn Coenen checkConnected(); 1234049f9d00a86f848d42d2429068496b31a6795adMartijn Coenen 1245289b91c885158094988a9a7b51b3139565eb639Martijn Coenen try { 1255289b91c885158094988a9a7b51b3139565eb639Martijn Coenen int serviceHandle = mTag.getServiceHandle(); 1264e21e1d21a877cce4db5ec8c5786604cc10f2d7eJeff Hamilton INfcTag tagService = mTag.getTagService(); 1274e21e1d21a877cce4db5ec8c5786604cc10f2d7eJeff Hamilton int errorCode = tagService.formatNdef(serviceHandle, MifareClassic.KEY_DEFAULT); 1285289b91c885158094988a9a7b51b3139565eb639Martijn Coenen switch (errorCode) { 1295289b91c885158094988a9a7b51b3139565eb639Martijn Coenen case ErrorCodes.SUCCESS: 1305289b91c885158094988a9a7b51b3139565eb639Martijn Coenen break; 1315289b91c885158094988a9a7b51b3139565eb639Martijn Coenen case ErrorCodes.ERROR_IO: 1325289b91c885158094988a9a7b51b3139565eb639Martijn Coenen throw new IOException(); 1335289b91c885158094988a9a7b51b3139565eb639Martijn Coenen case ErrorCodes.ERROR_INVALID_PARAM: 1345289b91c885158094988a9a7b51b3139565eb639Martijn Coenen throw new FormatException(); 1355289b91c885158094988a9a7b51b3139565eb639Martijn Coenen default: 1365289b91c885158094988a9a7b51b3139565eb639Martijn Coenen // Should not happen 1375289b91c885158094988a9a7b51b3139565eb639Martijn Coenen throw new IOException(); 1385289b91c885158094988a9a7b51b3139565eb639Martijn Coenen } 139e3f6336bcffc250da90ec864bccfa73ad1d016b9Martijn Coenen // Now check and see if the format worked 1402976da0305367ac051d0fcae160bfdb0497b2750Martijn Coenen if (!tagService.isNdef(serviceHandle)) { 1412976da0305367ac051d0fcae160bfdb0497b2750Martijn Coenen throw new IOException(); 1422976da0305367ac051d0fcae160bfdb0497b2750Martijn Coenen } 1432976da0305367ac051d0fcae160bfdb0497b2750Martijn Coenen 1442976da0305367ac051d0fcae160bfdb0497b2750Martijn Coenen // Write a message, if one was provided 1452976da0305367ac051d0fcae160bfdb0497b2750Martijn Coenen if (firstMessage != null) { 1464e21e1d21a877cce4db5ec8c5786604cc10f2d7eJeff Hamilton errorCode = tagService.ndefWrite(serviceHandle, firstMessage); 147e3f6336bcffc250da90ec864bccfa73ad1d016b9Martijn Coenen switch (errorCode) { 148e3f6336bcffc250da90ec864bccfa73ad1d016b9Martijn Coenen case ErrorCodes.SUCCESS: 149e3f6336bcffc250da90ec864bccfa73ad1d016b9Martijn Coenen break; 150e3f6336bcffc250da90ec864bccfa73ad1d016b9Martijn Coenen case ErrorCodes.ERROR_IO: 151e3f6336bcffc250da90ec864bccfa73ad1d016b9Martijn Coenen throw new IOException(); 152e3f6336bcffc250da90ec864bccfa73ad1d016b9Martijn Coenen case ErrorCodes.ERROR_INVALID_PARAM: 153e3f6336bcffc250da90ec864bccfa73ad1d016b9Martijn Coenen throw new FormatException(); 154e3f6336bcffc250da90ec864bccfa73ad1d016b9Martijn Coenen default: 155e3f6336bcffc250da90ec864bccfa73ad1d016b9Martijn Coenen // Should not happen 156e3f6336bcffc250da90ec864bccfa73ad1d016b9Martijn Coenen throw new IOException(); 157e3f6336bcffc250da90ec864bccfa73ad1d016b9Martijn Coenen } 1585289b91c885158094988a9a7b51b3139565eb639Martijn Coenen } 1592976da0305367ac051d0fcae160bfdb0497b2750Martijn Coenen 160f003e26df96067b4b136f0859012cb7ec3ed930fNick Pelly // optionally make read-only 161f003e26df96067b4b136f0859012cb7ec3ed930fNick Pelly if (makeReadOnly) { 162f003e26df96067b4b136f0859012cb7ec3ed930fNick Pelly errorCode = tagService.ndefMakeReadOnly(serviceHandle); 163f003e26df96067b4b136f0859012cb7ec3ed930fNick Pelly switch (errorCode) { 164f003e26df96067b4b136f0859012cb7ec3ed930fNick Pelly case ErrorCodes.SUCCESS: 165f003e26df96067b4b136f0859012cb7ec3ed930fNick Pelly break; 166f003e26df96067b4b136f0859012cb7ec3ed930fNick Pelly case ErrorCodes.ERROR_IO: 167f003e26df96067b4b136f0859012cb7ec3ed930fNick Pelly throw new IOException(); 168f003e26df96067b4b136f0859012cb7ec3ed930fNick Pelly case ErrorCodes.ERROR_INVALID_PARAM: 169f003e26df96067b4b136f0859012cb7ec3ed930fNick Pelly throw new IOException(); 170f003e26df96067b4b136f0859012cb7ec3ed930fNick Pelly default: 171f003e26df96067b4b136f0859012cb7ec3ed930fNick Pelly // Should not happen 172f003e26df96067b4b136f0859012cb7ec3ed930fNick Pelly throw new IOException(); 173f003e26df96067b4b136f0859012cb7ec3ed930fNick Pelly } 174f003e26df96067b4b136f0859012cb7ec3ed930fNick Pelly } 1755289b91c885158094988a9a7b51b3139565eb639Martijn Coenen } catch (RemoteException e) { 1763dd6c458530476eccb33bc05c9c9cd83823bcf8dNick Pelly Log.e(TAG, "NFC service dead", e); 1775289b91c885158094988a9a7b51b3139565eb639Martijn Coenen } 17839f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenen } 17939f91ed5290e8b27c795f8aec181a6dd4431d317Martijn Coenen} 180