blob: ffed8047966218e23fd96d4c2fee8e4b73f9ee30 [file] [log] [blame]
Nick Pelly367f41f2011-03-08 11:43:30 -08001/*
2 * Copyright (C) 2011 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 com.android.nfc_extras;
18
Nick Pelly678a7022011-11-14 14:22:52 -080019import java.util.HashMap;
20
Jeff Hamiltonbb951c82011-11-08 16:55:13 -060021import android.content.Context;
Nick Pelly367f41f2011-03-08 11:43:30 -080022import android.nfc.INfcAdapterExtras;
23import android.nfc.NfcAdapter;
24import android.os.RemoteException;
25import android.util.Log;
26
27/**
28 * Provides additional methods on an {@link NfcAdapter} for Card Emulation
29 * and management of {@link NfcExecutionEnvironment}'s.
30 *
31 * There is a 1-1 relationship between an {@link NfcAdapterExtras} object and
32 * a {@link NfcAdapter} object.
33 */
34public final class NfcAdapterExtras {
35 private static final String TAG = "NfcAdapterExtras";
36
37 /**
38 * Broadcast Action: an RF field ON has been detected.
39 *
40 * <p class="note">This is an unreliable signal, and will be removed.
41 * <p class="note">
42 * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission
43 * to receive.
44 */
45 public static final String ACTION_RF_FIELD_ON_DETECTED =
46 "com.android.nfc_extras.action.RF_FIELD_ON_DETECTED";
47
48 /**
49 * Broadcast Action: an RF field OFF has been detected.
50 *
51 * <p class="note">This is an unreliable signal, and will be removed.
52 * <p class="note">
53 * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission
54 * to receive.
55 */
56 public static final String ACTION_RF_FIELD_OFF_DETECTED =
57 "com.android.nfc_extras.action.RF_FIELD_OFF_DETECTED";
58
Nick Pellycc9ee722011-04-26 16:38:00 -070059 // protected by NfcAdapterExtras.class, and final after first construction,
60 // except for attemptDeadServiceRecovery() when NFC crashes - we accept a
61 // best effort recovery
Nick Pelly367f41f2011-03-08 11:43:30 -080062 private static INfcAdapterExtras sService;
Jeff Hamiltonbb951c82011-11-08 16:55:13 -060063 private static final CardEmulationRoute ROUTE_OFF =
64 new CardEmulationRoute(CardEmulationRoute.ROUTE_OFF, null);
65
Nick Pelly678a7022011-11-14 14:22:52 -080066 // contents protected by NfcAdapterExtras.class
67 private static final HashMap<NfcAdapter, NfcAdapterExtras> sNfcExtras = new HashMap();
68
Jeff Hamiltonbb951c82011-11-08 16:55:13 -060069 private final NfcExecutionEnvironment mEmbeddedEe;
70 private final CardEmulationRoute mRouteOnWhenScreenOn;
71
Nick Pelly678a7022011-11-14 14:22:52 -080072 private final NfcAdapter mAdapter;
Jeff Hamiltonbb951c82011-11-08 16:55:13 -060073 final String mPackageName;
Nick Pelly367f41f2011-03-08 11:43:30 -080074
Nick Pellycc9ee722011-04-26 16:38:00 -070075 /** get service handles */
Nick Pelly678a7022011-11-14 14:22:52 -080076 private static void initService(NfcAdapter adapter) {
77 final INfcAdapterExtras service = adapter.getNfcAdapterExtrasInterface();
Robert Tsai15bc8942011-07-09 23:57:22 -070078 if (service != null) {
79 // Leave stale rather than receive a null value.
80 sService = service;
81 }
Nick Pellycc9ee722011-04-26 16:38:00 -070082 }
83
Nick Pelly367f41f2011-03-08 11:43:30 -080084 /**
85 * Get the {@link NfcAdapterExtras} for the given {@link NfcAdapter}.
86 *
87 * <p class="note">
88 * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission.
89 *
90 * @param adapter a {@link NfcAdapter}, must not be null
91 * @return the {@link NfcAdapterExtras} object for the given {@link NfcAdapter}
92 */
93 public static NfcAdapterExtras get(NfcAdapter adapter) {
Jeff Hamiltonbb951c82011-11-08 16:55:13 -060094 Context context = adapter.getContext();
95 if (context == null) {
96 throw new UnsupportedOperationException(
97 "You must pass a context to your NfcAdapter to use the NFC extras APIs");
98 }
99
100 synchronized (NfcAdapterExtras.class) {
101 if (sService == null) {
Nick Pelly678a7022011-11-14 14:22:52 -0800102 initService(adapter);
Nick Pelly367f41f2011-03-08 11:43:30 -0800103 }
Nick Pelly678a7022011-11-14 14:22:52 -0800104 NfcAdapterExtras extras = sNfcExtras.get(adapter);
105 if (extras == null) {
106 extras = new NfcAdapterExtras(adapter);
107 sNfcExtras.put(adapter, extras);
108 }
109 return extras;
Nick Pelly367f41f2011-03-08 11:43:30 -0800110 }
111 }
112
Nick Pelly678a7022011-11-14 14:22:52 -0800113 private NfcAdapterExtras(NfcAdapter adapter) {
114 mAdapter = adapter;
115 mPackageName = adapter.getContext().getPackageName();
Jeff Hamiltonbb951c82011-11-08 16:55:13 -0600116 mEmbeddedEe = new NfcExecutionEnvironment(this);
117 mRouteOnWhenScreenOn = new CardEmulationRoute(CardEmulationRoute.ROUTE_ON_WHEN_SCREEN_ON,
118 mEmbeddedEe);
119 }
Nick Pelly367f41f2011-03-08 11:43:30 -0800120
121 /**
122 * Immutable data class that describes a card emulation route.
123 */
124 public final static class CardEmulationRoute {
125 /**
126 * Card Emulation is turned off on this NfcAdapter.
127 * <p>This is the default routing state after boot.
128 */
129 public static final int ROUTE_OFF = 1;
130
131 /**
132 * Card Emulation is routed to {@link #nfcEe} only when the screen is on,
133 * otherwise it is turned off.
134 */
135 public static final int ROUTE_ON_WHEN_SCREEN_ON = 2;
136
137 /**
138 * A route such as {@link #ROUTE_OFF} or {@link #ROUTE_ON_WHEN_SCREEN_ON}.
139 */
140 public final int route;
141
142 /**
143 * The {@link NFcExecutionEnvironment} that is Card Emulation is routed to.
144 * <p>null if {@link #route} is {@link #ROUTE_OFF}, otherwise not null.
145 */
146 public final NfcExecutionEnvironment nfcEe;
147
148 public CardEmulationRoute(int route, NfcExecutionEnvironment nfcEe) {
149 if (route == ROUTE_OFF && nfcEe != null) {
150 throw new IllegalArgumentException("must not specifiy a NFC-EE with ROUTE_OFF");
151 } else if (route != ROUTE_OFF && nfcEe == null) {
152 throw new IllegalArgumentException("must specifiy a NFC-EE for this route");
153 }
154 this.route = route;
155 this.nfcEe = nfcEe;
156 }
157 }
158
159 /**
Nick Pellycc9ee722011-04-26 16:38:00 -0700160 * NFC service dead - attempt best effort recovery
161 */
162 void attemptDeadServiceRecovery(Exception e) {
163 Log.e(TAG, "NFC Adapter Extras dead - attempting to recover");
Nick Pelly678a7022011-11-14 14:22:52 -0800164 mAdapter.attemptDeadServiceRecovery(e);
165 initService(mAdapter);
Nick Pellycc9ee722011-04-26 16:38:00 -0700166 }
167
168 INfcAdapterExtras getService() {
169 return sService;
170 }
171
172 /**
Nick Pelly367f41f2011-03-08 11:43:30 -0800173 * Get the routing state of this NFC EE.
174 *
175 * <p class="note">
176 * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission.
Nick Pelly367f41f2011-03-08 11:43:30 -0800177 */
178 public CardEmulationRoute getCardEmulationRoute() {
179 try {
Jeff Hamiltonbb951c82011-11-08 16:55:13 -0600180 int route = sService.getCardEmulationRoute(mPackageName);
Nick Pelly367f41f2011-03-08 11:43:30 -0800181 return route == CardEmulationRoute.ROUTE_OFF ?
Jeff Hamiltonbb951c82011-11-08 16:55:13 -0600182 ROUTE_OFF :
183 mRouteOnWhenScreenOn;
Nick Pelly367f41f2011-03-08 11:43:30 -0800184 } catch (RemoteException e) {
Nick Pellycc9ee722011-04-26 16:38:00 -0700185 attemptDeadServiceRecovery(e);
Jeff Hamiltonbb951c82011-11-08 16:55:13 -0600186 return ROUTE_OFF;
Nick Pelly367f41f2011-03-08 11:43:30 -0800187 }
188 }
189
190 /**
191 * Set the routing state of this NFC EE.
192 *
193 * <p>This routing state is not persisted across reboot.
194 *
195 * <p class="note">
196 * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission.
197 *
Jeff Hamiltonbb951c82011-11-08 16:55:13 -0600198 * @param route a {@link CardEmulationRoute}
Nick Pelly367f41f2011-03-08 11:43:30 -0800199 */
200 public void setCardEmulationRoute(CardEmulationRoute route) {
201 try {
Jeff Hamiltonbb951c82011-11-08 16:55:13 -0600202 sService.setCardEmulationRoute(mPackageName, route.route);
Nick Pelly367f41f2011-03-08 11:43:30 -0800203 } catch (RemoteException e) {
Nick Pellycc9ee722011-04-26 16:38:00 -0700204 attemptDeadServiceRecovery(e);
Nick Pelly367f41f2011-03-08 11:43:30 -0800205 }
206 }
207
208 /**
209 * Get the {@link NfcExecutionEnvironment} that is embedded with the
Jeff Hamiltonbb951c82011-11-08 16:55:13 -0600210 * {@link NfcAdapter}.
Nick Pelly367f41f2011-03-08 11:43:30 -0800211 *
212 * <p class="note">
213 * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission.
214 *
215 * @return a {@link NfcExecutionEnvironment}, or null if there is no embedded NFC-EE
216 */
217 public NfcExecutionEnvironment getEmbeddedExecutionEnvironment() {
Jeff Hamiltonbb951c82011-11-08 16:55:13 -0600218 return mEmbeddedEe;
Nick Pelly367f41f2011-03-08 11:43:30 -0800219 }
Jason parksab8f48c2011-03-31 13:15:18 -0500220
Nick Pelly17523ab2011-06-17 10:56:39 -0700221 /**
222 * Authenticate the client application.
223 *
224 * Some implementations of NFC Adapter Extras may require applications
225 * to authenticate with a token, before using other methods.
226 *
Jeff Hamiltonbb951c82011-11-08 16:55:13 -0600227 * @param token a implementation specific token
228 * @throws java.lang.SecurityException if authentication failed
Nick Pelly17523ab2011-06-17 10:56:39 -0700229 */
230 public void authenticate(byte[] token) {
Jason parksab8f48c2011-03-31 13:15:18 -0500231 try {
Jeff Hamiltonbb951c82011-11-08 16:55:13 -0600232 sService.authenticate(mPackageName, token);
Jason parksab8f48c2011-03-31 13:15:18 -0500233 } catch (RemoteException e) {
Nick Pellycc9ee722011-04-26 16:38:00 -0700234 attemptDeadServiceRecovery(e);
Jason parksab8f48c2011-03-31 13:15:18 -0500235 }
236 }
mike wakerlyf74df472012-10-03 13:45:00 -0700237
238 /**
239 * Returns the name of this adapter's driver.
240 *
241 * <p>Different NFC adapters may use different drivers. This value is
242 * informational and should not be parsed.
243 *
244 * @return the driver name, or empty string if unknown
245 */
246 public String getDriverName() {
247 try {
248 return sService.getDriverName(mPackageName);
249 } catch (RemoteException e) {
250 attemptDeadServiceRecovery(e);
251 return "";
252 }
253 }
Nick Pelly367f41f2011-03-08 11:43:30 -0800254}