blob: 4175cd08804c20bd7c878cdacf97e3e791e79139 [file] [log] [blame]
Martijn Coenen39f91ed2010-12-06 18:11:12 -08001/*
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 Hamilton4e21e1d2011-01-21 01:13:06 -060017package android.nfc.tech;
Martijn Coenen39f91ed2010-12-06 18:11:12 -080018
19import android.nfc.ErrorCodes;
20import android.nfc.FormatException;
Jeff Hamilton4e21e1d2011-01-21 01:13:06 -060021import android.nfc.INfcTag;
Martijn Coenen39f91ed2010-12-06 18:11:12 -080022import android.nfc.NdefMessage;
Martijn Coenen39f91ed2010-12-06 18:11:12 -080023import android.nfc.Tag;
Nick Pelly74fe6c62011-02-02 22:37:40 -080024import android.nfc.TagLostException;
Martijn Coenen39f91ed2010-12-06 18:11:12 -080025import android.os.RemoteException;
Nick Pelly3dd6c452011-01-10 18:14:41 +110026import android.util.Log;
Martijn Coenen39f91ed2010-12-06 18:11:12 -080027
28import java.io.IOException;
29
30/**
Nick Pelly74fe6c62011-02-02 22:37:40 -080031 * Provide access to NDEF format operations on a {@link Tag}.
Martijn Coenen39f91ed2010-12-06 18:11:12 -080032 *
Nick Pelly74fe6c62011-02-02 22:37:40 -080033 * <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 Coenen39f91ed2010-12-06 18:11:12 -080042 *
Nick Pelly39cf3a42011-02-07 17:04:21 +090043 * <p class="note"><strong>Note:</strong> Methods that perform I/O operations
44 * require the {@link android.Manifest.permission#NFC} permission.
Martijn Coenen39f91ed2010-12-06 18:11:12 -080045 */
46public final class NdefFormatable extends BasicTagTechnology {
Nick Pelly3dd6c452011-01-10 18:14:41 +110047 private static final String TAG = "NFC";
48
Martijn Coenen39f91ed2010-12-06 18:11:12 -080049 /**
Nick Pelly74fe6c62011-02-02 22:37:40 -080050 * 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 Hamilton4e21e1d2011-01-21 01:13:06 -060054 *
Nick Pelly74fe6c62011-02-02 22:37:40 -080055 * @param tag an NDEF formatable tag
56 * @return NDEF formatable object
Jeff Hamilton4e21e1d2011-01-21 01:13:06 -060057 */
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 Coenen39f91ed2010-12-06 18:11:12 -080068 * Internal constructor, to be used by NfcAdapter
69 * @hide
70 */
Jeff Hamilton4e21e1d2011-01-21 01:13:06 -060071 public NdefFormatable(Tag tag) throws RemoteException {
72 super(tag, TagTechnology.NDEF_FORMATABLE);
Martijn Coenen39f91ed2010-12-06 18:11:12 -080073 }
74
75 /**
Nick Pelly74fe6c62011-02-02 22:37:40 -080076 * 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 Pelly39cf3a42011-02-07 17:04:21 +090086 * <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 Pelly74fe6c62011-02-02 22:37:40 -080089 * @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 Coenen39f91ed2010-12-06 18:11:12 -080092 */
Nick Pelly46797ac2011-02-03 16:06:53 -080093 public void format(NdefMessage firstMessage) throws IOException, FormatException {
94 format(firstMessage, false);
Nick Pellyf003e262011-01-31 23:27:37 -080095 }
96
97 /**
Nick Pelly74fe6c62011-02-02 22:37:40 -080098 * 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 Pelly39cf3a42011-02-07 17:04:21 +0900108 * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
109 *
Nick Pelly46797ac2011-02-03 16:06:53 -0800110 * @param firstMessage the NDEF message to write after formatting
Nick Pelly74fe6c62011-02-02 22:37:40 -0800111 * @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 Pellyf003e262011-01-31 23:27:37 -0800114 */
Nick Pelly46797ac2011-02-03 16:06:53 -0800115 public void formatReadOnly(NdefMessage firstMessage) throws IOException, FormatException {
116 format(firstMessage, true);
Nick Pellyf003e262011-01-31 23:27:37 -0800117 }
118
119 /*package*/ void format(NdefMessage firstMessage, boolean makeReadOnly) throws IOException,
120 FormatException {
Martijn Coenen4049f9d02010-12-14 16:58:27 +0100121 checkConnected();
122
Martijn Coenen5289b912010-12-07 18:01:35 -0800123 try {
Martijn Coenen5289b912010-12-07 18:01:35 -0800124 int serviceHandle = mTag.getServiceHandle();
Jeff Hamilton4e21e1d2011-01-21 01:13:06 -0600125 INfcTag tagService = mTag.getTagService();
126 int errorCode = tagService.formatNdef(serviceHandle, MifareClassic.KEY_DEFAULT);
Martijn Coenen5289b912010-12-07 18:01:35 -0800127 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 Coenene3f63362010-12-13 16:18:41 +0100138 // Now check and see if the format worked
Martijn Coenen2976da02012-03-29 10:09:19 -0700139 if (!tagService.isNdef(serviceHandle)) {
140 throw new IOException();
141 }
142
143 // Write a message, if one was provided
144 if (firstMessage != null) {
Jeff Hamilton4e21e1d2011-01-21 01:13:06 -0600145 errorCode = tagService.ndefWrite(serviceHandle, firstMessage);
Martijn Coenene3f63362010-12-13 16:18:41 +0100146 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 Coenen5289b912010-12-07 18:01:35 -0800157 }
Martijn Coenen2976da02012-03-29 10:09:19 -0700158
Nick Pellyf003e262011-01-31 23:27:37 -0800159 // 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 Coenen5289b912010-12-07 18:01:35 -0800174 } catch (RemoteException e) {
Nick Pelly3dd6c452011-01-10 18:14:41 +1100175 Log.e(TAG, "NFC service dead", e);
Martijn Coenen5289b912010-12-07 18:01:35 -0800176 }
Martijn Coenen39f91ed2010-12-06 18:11:12 -0800177 }
Martijn Coenen39f91ed2010-12-06 18:11:12 -0800178}