Martijn Coenen | 39f91ed | 2010-12-06 18:11:12 -0800 | [diff] [blame] | 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 | |
Jeff Hamilton | 4e21e1d | 2011-01-21 01:13:06 -0600 | [diff] [blame] | 17 | package android.nfc.tech; |
Martijn Coenen | 39f91ed | 2010-12-06 18:11:12 -0800 | [diff] [blame] | 18 | |
| 19 | import android.nfc.ErrorCodes; |
| 20 | import android.nfc.FormatException; |
Jeff Hamilton | 4e21e1d | 2011-01-21 01:13:06 -0600 | [diff] [blame] | 21 | import android.nfc.INfcTag; |
Martijn Coenen | 39f91ed | 2010-12-06 18:11:12 -0800 | [diff] [blame] | 22 | import android.nfc.NdefMessage; |
Martijn Coenen | 39f91ed | 2010-12-06 18:11:12 -0800 | [diff] [blame] | 23 | import android.nfc.Tag; |
Nick Pelly | 74fe6c6 | 2011-02-02 22:37:40 -0800 | [diff] [blame] | 24 | import android.nfc.TagLostException; |
Martijn Coenen | 39f91ed | 2010-12-06 18:11:12 -0800 | [diff] [blame] | 25 | import android.os.RemoteException; |
Nick Pelly | 3dd6c45 | 2011-01-10 18:14:41 +1100 | [diff] [blame] | 26 | import android.util.Log; |
Martijn Coenen | 39f91ed | 2010-12-06 18:11:12 -0800 | [diff] [blame] | 27 | |
| 28 | import java.io.IOException; |
| 29 | |
| 30 | /** |
Nick Pelly | 74fe6c6 | 2011-02-02 22:37:40 -0800 | [diff] [blame] | 31 | * Provide access to NDEF format operations on a {@link Tag}. |
Martijn Coenen | 39f91ed | 2010-12-06 18:11:12 -0800 | [diff] [blame] | 32 | * |
Nick Pelly | 74fe6c6 | 2011-02-02 22:37:40 -0800 | [diff] [blame] | 33 | * <p>Acquire a {@link NdefFormatable} object using {@link #get}. |
| 34 | * |
| 35 | * <p>Android devices with NFC must only enumerate and implement this |
| 36 | * class for tags for which it can format to NDEF. |
| 37 | * |
| 38 | * <p>Unfortunately the procedures to convert unformated tags to NDEF formatted |
| 39 | * tags are not specified by NFC Forum, and are not generally well-known. So |
| 40 | * there is no mandatory set of tags for which all Android devices with NFC |
| 41 | * must support {@link NdefFormatable}. |
Martijn Coenen | 39f91ed | 2010-12-06 18:11:12 -0800 | [diff] [blame] | 42 | * |
Nick Pelly | 39cf3a4 | 2011-02-07 17:04:21 +0900 | [diff] [blame] | 43 | * <p class="note"><strong>Note:</strong> Methods that perform I/O operations |
| 44 | * require the {@link android.Manifest.permission#NFC} permission. |
Martijn Coenen | 39f91ed | 2010-12-06 18:11:12 -0800 | [diff] [blame] | 45 | */ |
| 46 | public final class NdefFormatable extends BasicTagTechnology { |
Nick Pelly | 3dd6c45 | 2011-01-10 18:14:41 +1100 | [diff] [blame] | 47 | private static final String TAG = "NFC"; |
| 48 | |
Martijn Coenen | 39f91ed | 2010-12-06 18:11:12 -0800 | [diff] [blame] | 49 | /** |
Nick Pelly | 74fe6c6 | 2011-02-02 22:37:40 -0800 | [diff] [blame] | 50 | * Get an instance of {@link NdefFormatable} for the given tag. |
| 51 | * <p>Does not cause any RF activity and does not block. |
| 52 | * <p>Returns null if {@link NdefFormatable} was not enumerated in {@link Tag#getTechList}. |
| 53 | * This indicates the tag is not NDEF formatable by this Android device. |
Jeff Hamilton | 4e21e1d | 2011-01-21 01:13:06 -0600 | [diff] [blame] | 54 | * |
Nick Pelly | 74fe6c6 | 2011-02-02 22:37:40 -0800 | [diff] [blame] | 55 | * @param tag an NDEF formatable tag |
| 56 | * @return NDEF formatable object |
Jeff Hamilton | 4e21e1d | 2011-01-21 01:13:06 -0600 | [diff] [blame] | 57 | */ |
| 58 | public static NdefFormatable get(Tag tag) { |
| 59 | if (!tag.hasTech(TagTechnology.NDEF_FORMATABLE)) return null; |
| 60 | try { |
| 61 | return new NdefFormatable(tag); |
| 62 | } catch (RemoteException e) { |
| 63 | return null; |
| 64 | } |
| 65 | } |
| 66 | |
| 67 | /** |
Martijn Coenen | 39f91ed | 2010-12-06 18:11:12 -0800 | [diff] [blame] | 68 | * Internal constructor, to be used by NfcAdapter |
| 69 | * @hide |
| 70 | */ |
Jeff Hamilton | 4e21e1d | 2011-01-21 01:13:06 -0600 | [diff] [blame] | 71 | public NdefFormatable(Tag tag) throws RemoteException { |
| 72 | super(tag, TagTechnology.NDEF_FORMATABLE); |
Martijn Coenen | 39f91ed | 2010-12-06 18:11:12 -0800 | [diff] [blame] | 73 | } |
| 74 | |
| 75 | /** |
Nick Pelly | 74fe6c6 | 2011-02-02 22:37:40 -0800 | [diff] [blame] | 76 | * Format a tag as NDEF, and write a {@link NdefMessage}. |
| 77 | * |
| 78 | * <p>This is a multi-step process, an IOException is thrown |
| 79 | * if any one step fails. |
| 80 | * <p>The card is left in a read-write state after this operation. |
| 81 | * |
| 82 | * <p>This is an I/O operation and will block until complete. It must |
| 83 | * not be called from the main application thread. A blocked call will be canceled with |
| 84 | * {@link IOException} if {@link #close} is called from another thread. |
| 85 | * |
Nick Pelly | 39cf3a4 | 2011-02-07 17:04:21 +0900 | [diff] [blame] | 86 | * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. |
| 87 | * |
| 88 | * @param firstMessage the NDEF message to write after formatting, can be null |
Nick Pelly | 74fe6c6 | 2011-02-02 22:37:40 -0800 | [diff] [blame] | 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 |
Martijn Coenen | 39f91ed | 2010-12-06 18:11:12 -0800 | [diff] [blame] | 92 | */ |
Nick Pelly | 46797ac | 2011-02-03 16:06:53 -0800 | [diff] [blame] | 93 | public void format(NdefMessage firstMessage) throws IOException, FormatException { |
| 94 | format(firstMessage, false); |
Nick Pelly | f003e26 | 2011-01-31 23:27:37 -0800 | [diff] [blame] | 95 | } |
| 96 | |
| 97 | /** |
Nick Pelly | 74fe6c6 | 2011-02-02 22:37:40 -0800 | [diff] [blame] | 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 | * |
Nick Pelly | 39cf3a4 | 2011-02-07 17:04:21 +0900 | [diff] [blame] | 108 | * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. |
| 109 | * |
Nick Pelly | 46797ac | 2011-02-03 16:06:53 -0800 | [diff] [blame] | 110 | * @param firstMessage the NDEF message to write after formatting |
Nick Pelly | 74fe6c6 | 2011-02-02 22:37:40 -0800 | [diff] [blame] | 111 | * @throws TagLostException if the tag leaves the field |
| 112 | * @throws IOException if there is an I/O failure, or the operation is canceled |
| 113 | * @throws FormatException if the NDEF Message to write is malformed |
Nick Pelly | f003e26 | 2011-01-31 23:27:37 -0800 | [diff] [blame] | 114 | */ |
Nick Pelly | 46797ac | 2011-02-03 16:06:53 -0800 | [diff] [blame] | 115 | public void formatReadOnly(NdefMessage firstMessage) throws IOException, FormatException { |
| 116 | format(firstMessage, true); |
Nick Pelly | f003e26 | 2011-01-31 23:27:37 -0800 | [diff] [blame] | 117 | } |
| 118 | |
| 119 | /*package*/ void format(NdefMessage firstMessage, boolean makeReadOnly) throws IOException, |
| 120 | FormatException { |
Martijn Coenen | 4049f9d0 | 2010-12-14 16:58:27 +0100 | [diff] [blame] | 121 | checkConnected(); |
| 122 | |
Martijn Coenen | 5289b91 | 2010-12-07 18:01:35 -0800 | [diff] [blame] | 123 | try { |
Martijn Coenen | 5289b91 | 2010-12-07 18:01:35 -0800 | [diff] [blame] | 124 | int serviceHandle = mTag.getServiceHandle(); |
Jeff Hamilton | 4e21e1d | 2011-01-21 01:13:06 -0600 | [diff] [blame] | 125 | INfcTag tagService = mTag.getTagService(); |
| 126 | int errorCode = tagService.formatNdef(serviceHandle, MifareClassic.KEY_DEFAULT); |
Martijn Coenen | 5289b91 | 2010-12-07 18:01:35 -0800 | [diff] [blame] | 127 | switch (errorCode) { |
| 128 | case ErrorCodes.SUCCESS: |
| 129 | break; |
| 130 | case ErrorCodes.ERROR_IO: |
| 131 | throw new IOException(); |
| 132 | case ErrorCodes.ERROR_INVALID_PARAM: |
| 133 | throw new FormatException(); |
| 134 | default: |
| 135 | // Should not happen |
| 136 | throw new IOException(); |
| 137 | } |
Martijn Coenen | e3f6336 | 2010-12-13 16:18:41 +0100 | [diff] [blame] | 138 | // Now check and see if the format worked |
Martijn Coenen | 2976da0 | 2012-03-29 10:09:19 -0700 | [diff] [blame] | 139 | if (!tagService.isNdef(serviceHandle)) { |
| 140 | throw new IOException(); |
| 141 | } |
| 142 | |
| 143 | // Write a message, if one was provided |
| 144 | if (firstMessage != null) { |
Jeff Hamilton | 4e21e1d | 2011-01-21 01:13:06 -0600 | [diff] [blame] | 145 | errorCode = tagService.ndefWrite(serviceHandle, firstMessage); |
Martijn Coenen | e3f6336 | 2010-12-13 16:18:41 +0100 | [diff] [blame] | 146 | switch (errorCode) { |
| 147 | case ErrorCodes.SUCCESS: |
| 148 | break; |
| 149 | case ErrorCodes.ERROR_IO: |
| 150 | throw new IOException(); |
| 151 | case ErrorCodes.ERROR_INVALID_PARAM: |
| 152 | throw new FormatException(); |
| 153 | default: |
| 154 | // Should not happen |
| 155 | throw new IOException(); |
| 156 | } |
Martijn Coenen | 5289b91 | 2010-12-07 18:01:35 -0800 | [diff] [blame] | 157 | } |
Martijn Coenen | 2976da0 | 2012-03-29 10:09:19 -0700 | [diff] [blame] | 158 | |
Nick Pelly | f003e26 | 2011-01-31 23:27:37 -0800 | [diff] [blame] | 159 | // optionally make read-only |
| 160 | if (makeReadOnly) { |
| 161 | errorCode = tagService.ndefMakeReadOnly(serviceHandle); |
| 162 | switch (errorCode) { |
| 163 | case ErrorCodes.SUCCESS: |
| 164 | break; |
| 165 | case ErrorCodes.ERROR_IO: |
| 166 | throw new IOException(); |
| 167 | case ErrorCodes.ERROR_INVALID_PARAM: |
| 168 | throw new IOException(); |
| 169 | default: |
| 170 | // Should not happen |
| 171 | throw new IOException(); |
| 172 | } |
| 173 | } |
Martijn Coenen | 5289b91 | 2010-12-07 18:01:35 -0800 | [diff] [blame] | 174 | } catch (RemoteException e) { |
Nick Pelly | 3dd6c45 | 2011-01-10 18:14:41 +1100 | [diff] [blame] | 175 | Log.e(TAG, "NFC service dead", e); |
Martijn Coenen | 5289b91 | 2010-12-07 18:01:35 -0800 | [diff] [blame] | 176 | } |
Martijn Coenen | 39f91ed | 2010-12-06 18:11:12 -0800 | [diff] [blame] | 177 | } |
Martijn Coenen | 39f91ed | 2010-12-06 18:11:12 -0800 | [diff] [blame] | 178 | } |