NdefFormatable.java revision 74fe6c6b245ebe7d3b3d96962c32980d88dca4f5
1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.nfc.tech; 18 19import android.nfc.ErrorCodes; 20import android.nfc.FormatException; 21import android.nfc.INfcTag; 22import android.nfc.NdefMessage; 23import android.nfc.NfcAdapter; 24import android.nfc.Tag; 25import android.nfc.TagLostException; 26import android.os.RemoteException; 27import android.util.Log; 28 29import java.io.IOException; 30 31/** 32 * Provide access to NDEF format operations on a {@link Tag}. 33 * 34 * <p>Acquire a {@link NdefFormatable} object using {@link #get}. 35 * 36 * <p>Android devices with NFC must only enumerate and implement this 37 * class for tags for which it can format to NDEF. 38 * 39 * <p>Unfortunately the procedures to convert unformated tags to NDEF formatted 40 * tags are not specified by NFC Forum, and are not generally well-known. So 41 * there is no mandatory set of tags for which all Android devices with NFC 42 * must support {@link NdefFormatable}. 43 * 44 * <p class="note"><strong>Note:</strong> 45 * Use of this class requires the {@link android.Manifest.permission#NFC} 46 * permission. 47 */ 48public final class NdefFormatable extends BasicTagTechnology { 49 private static final String TAG = "NFC"; 50 51 /** 52 * Get an instance of {@link NdefFormatable} for the given tag. 53 * <p>Does not cause any RF activity and does not block. 54 * <p>Returns null if {@link NdefFormatable} was not enumerated in {@link Tag#getTechList}. 55 * This indicates the tag is not NDEF formatable by this Android device. 56 * 57 * @param tag an NDEF formatable tag 58 * @return NDEF formatable object 59 */ 60 public static NdefFormatable get(Tag tag) { 61 if (!tag.hasTech(TagTechnology.NDEF_FORMATABLE)) return null; 62 try { 63 return new NdefFormatable(tag); 64 } catch (RemoteException e) { 65 return null; 66 } 67 } 68 69 /** 70 * Internal constructor, to be used by NfcAdapter 71 * @hide 72 */ 73 public NdefFormatable(Tag tag) throws RemoteException { 74 super(tag, TagTechnology.NDEF_FORMATABLE); 75 } 76 77 /** 78 * Format a tag as NDEF, and write a {@link NdefMessage}. 79 * 80 * <p>This is a multi-step process, an IOException is thrown 81 * if any one step fails. 82 * <p>The card is left in a read-write state after this operation. 83 * 84 * <p>This is an I/O operation and will block until complete. It must 85 * not be called from the main application thread. A blocked call will be canceled with 86 * {@link IOException} if {@link #close} is called from another thread. 87 * 88 * @param msg the NDEF message to write after formatting 89 * @throws TagLostException if the tag leaves the field 90 * @throws IOException if there is an I/O failure, or the operation is canceled 91 * @throws FormatException if the NDEF Message to write is malformed 92 */ 93 public void format(NdefMessage msg) throws IOException, FormatException { 94 format(msg, false); 95 } 96 97 /** 98 * Formats a tag as NDEF, write a {@link NdefMessage}, and make read-only. 99 * 100 * <p>This is a multi-step process, an IOException is thrown 101 * if any one step fails. 102 * <p>The card is left in a read-only state if this method returns successfully. 103 * 104 * <p>This is an I/O operation and will block until complete. It must 105 * not be called from the main application thread. A blocked call will be canceled with 106 * {@link IOException} if {@link #close} is called from another thread. 107 * 108 * @param msg the NDEF message to write after formatting 109 * @throws TagLostException if the tag leaves the field 110 * @throws IOException if there is an I/O failure, or the operation is canceled 111 * @throws FormatException if the NDEF Message to write is malformed 112 */ 113 public void formatReadOnly(NdefMessage msg) throws IOException, FormatException { 114 format(msg, true); 115 } 116 117 /*package*/ void format(NdefMessage firstMessage, boolean makeReadOnly) throws IOException, 118 FormatException { 119 checkConnected(); 120 121 try { 122 int serviceHandle = mTag.getServiceHandle(); 123 INfcTag tagService = mTag.getTagService(); 124 int errorCode = tagService.formatNdef(serviceHandle, MifareClassic.KEY_DEFAULT); 125 switch (errorCode) { 126 case ErrorCodes.SUCCESS: 127 break; 128 case ErrorCodes.ERROR_IO: 129 throw new IOException(); 130 case ErrorCodes.ERROR_INVALID_PARAM: 131 throw new FormatException(); 132 default: 133 // Should not happen 134 throw new IOException(); 135 } 136 // Now check and see if the format worked 137 if (tagService.isNdef(serviceHandle)) { 138 errorCode = tagService.ndefWrite(serviceHandle, firstMessage); 139 switch (errorCode) { 140 case ErrorCodes.SUCCESS: 141 break; 142 case ErrorCodes.ERROR_IO: 143 throw new IOException(); 144 case ErrorCodes.ERROR_INVALID_PARAM: 145 throw new FormatException(); 146 default: 147 // Should not happen 148 throw new IOException(); 149 } 150 } else { 151 throw new IOException(); 152 } 153 // optionally make read-only 154 if (makeReadOnly) { 155 errorCode = tagService.ndefMakeReadOnly(serviceHandle); 156 switch (errorCode) { 157 case ErrorCodes.SUCCESS: 158 break; 159 case ErrorCodes.ERROR_IO: 160 throw new IOException(); 161 case ErrorCodes.ERROR_INVALID_PARAM: 162 throw new IOException(); 163 default: 164 // Should not happen 165 throw new IOException(); 166 } 167 } 168 } catch (RemoteException e) { 169 Log.e(TAG, "NFC service dead", e); 170 } 171 } 172} 173