Nick Pelly | 367f41f | 2011-03-08 11:43:30 -0800 | [diff] [blame] | 1 | /* |
| 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 | |
| 17 | package com.android.nfc_extras; |
| 18 | |
Nick Pelly | 678a702 | 2011-11-14 14:22:52 -0800 | [diff] [blame] | 19 | import java.util.HashMap; |
| 20 | |
Jeff Hamilton | bb951c8 | 2011-11-08 16:55:13 -0600 | [diff] [blame] | 21 | import android.content.Context; |
Nick Pelly | 367f41f | 2011-03-08 11:43:30 -0800 | [diff] [blame] | 22 | import android.nfc.INfcAdapterExtras; |
| 23 | import android.nfc.NfcAdapter; |
| 24 | import android.os.RemoteException; |
| 25 | import 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 | */ |
| 34 | public 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 Pelly | cc9ee72 | 2011-04-26 16:38:00 -0700 | [diff] [blame] | 59 | // protected by NfcAdapterExtras.class, and final after first construction, |
| 60 | // except for attemptDeadServiceRecovery() when NFC crashes - we accept a |
| 61 | // best effort recovery |
Nick Pelly | 367f41f | 2011-03-08 11:43:30 -0800 | [diff] [blame] | 62 | private static INfcAdapterExtras sService; |
Jeff Hamilton | bb951c8 | 2011-11-08 16:55:13 -0600 | [diff] [blame] | 63 | private static final CardEmulationRoute ROUTE_OFF = |
| 64 | new CardEmulationRoute(CardEmulationRoute.ROUTE_OFF, null); |
| 65 | |
Nick Pelly | 678a702 | 2011-11-14 14:22:52 -0800 | [diff] [blame] | 66 | // contents protected by NfcAdapterExtras.class |
| 67 | private static final HashMap<NfcAdapter, NfcAdapterExtras> sNfcExtras = new HashMap(); |
| 68 | |
Jeff Hamilton | bb951c8 | 2011-11-08 16:55:13 -0600 | [diff] [blame] | 69 | private final NfcExecutionEnvironment mEmbeddedEe; |
| 70 | private final CardEmulationRoute mRouteOnWhenScreenOn; |
| 71 | |
Nick Pelly | 678a702 | 2011-11-14 14:22:52 -0800 | [diff] [blame] | 72 | private final NfcAdapter mAdapter; |
Jeff Hamilton | bb951c8 | 2011-11-08 16:55:13 -0600 | [diff] [blame] | 73 | final String mPackageName; |
Nick Pelly | 367f41f | 2011-03-08 11:43:30 -0800 | [diff] [blame] | 74 | |
Nick Pelly | cc9ee72 | 2011-04-26 16:38:00 -0700 | [diff] [blame] | 75 | /** get service handles */ |
Nick Pelly | 678a702 | 2011-11-14 14:22:52 -0800 | [diff] [blame] | 76 | private static void initService(NfcAdapter adapter) { |
| 77 | final INfcAdapterExtras service = adapter.getNfcAdapterExtrasInterface(); |
Robert Tsai | 15bc894 | 2011-07-09 23:57:22 -0700 | [diff] [blame] | 78 | if (service != null) { |
| 79 | // Leave stale rather than receive a null value. |
| 80 | sService = service; |
| 81 | } |
Nick Pelly | cc9ee72 | 2011-04-26 16:38:00 -0700 | [diff] [blame] | 82 | } |
| 83 | |
Nick Pelly | 367f41f | 2011-03-08 11:43:30 -0800 | [diff] [blame] | 84 | /** |
| 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 Hamilton | bb951c8 | 2011-11-08 16:55:13 -0600 | [diff] [blame] | 94 | 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 Pelly | 678a702 | 2011-11-14 14:22:52 -0800 | [diff] [blame] | 102 | initService(adapter); |
Nick Pelly | 367f41f | 2011-03-08 11:43:30 -0800 | [diff] [blame] | 103 | } |
Nick Pelly | 678a702 | 2011-11-14 14:22:52 -0800 | [diff] [blame] | 104 | NfcAdapterExtras extras = sNfcExtras.get(adapter); |
| 105 | if (extras == null) { |
| 106 | extras = new NfcAdapterExtras(adapter); |
| 107 | sNfcExtras.put(adapter, extras); |
| 108 | } |
| 109 | return extras; |
Nick Pelly | 367f41f | 2011-03-08 11:43:30 -0800 | [diff] [blame] | 110 | } |
| 111 | } |
| 112 | |
Nick Pelly | 678a702 | 2011-11-14 14:22:52 -0800 | [diff] [blame] | 113 | private NfcAdapterExtras(NfcAdapter adapter) { |
| 114 | mAdapter = adapter; |
| 115 | mPackageName = adapter.getContext().getPackageName(); |
Jeff Hamilton | bb951c8 | 2011-11-08 16:55:13 -0600 | [diff] [blame] | 116 | mEmbeddedEe = new NfcExecutionEnvironment(this); |
| 117 | mRouteOnWhenScreenOn = new CardEmulationRoute(CardEmulationRoute.ROUTE_ON_WHEN_SCREEN_ON, |
| 118 | mEmbeddedEe); |
| 119 | } |
Nick Pelly | 367f41f | 2011-03-08 11:43:30 -0800 | [diff] [blame] | 120 | |
| 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 Pelly | cc9ee72 | 2011-04-26 16:38:00 -0700 | [diff] [blame] | 160 | * 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 Pelly | 678a702 | 2011-11-14 14:22:52 -0800 | [diff] [blame] | 164 | mAdapter.attemptDeadServiceRecovery(e); |
| 165 | initService(mAdapter); |
Nick Pelly | cc9ee72 | 2011-04-26 16:38:00 -0700 | [diff] [blame] | 166 | } |
| 167 | |
| 168 | INfcAdapterExtras getService() { |
| 169 | return sService; |
| 170 | } |
| 171 | |
| 172 | /** |
Nick Pelly | 367f41f | 2011-03-08 11:43:30 -0800 | [diff] [blame] | 173 | * 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 Pelly | 367f41f | 2011-03-08 11:43:30 -0800 | [diff] [blame] | 177 | */ |
| 178 | public CardEmulationRoute getCardEmulationRoute() { |
| 179 | try { |
Jeff Hamilton | bb951c8 | 2011-11-08 16:55:13 -0600 | [diff] [blame] | 180 | int route = sService.getCardEmulationRoute(mPackageName); |
Nick Pelly | 367f41f | 2011-03-08 11:43:30 -0800 | [diff] [blame] | 181 | return route == CardEmulationRoute.ROUTE_OFF ? |
Jeff Hamilton | bb951c8 | 2011-11-08 16:55:13 -0600 | [diff] [blame] | 182 | ROUTE_OFF : |
| 183 | mRouteOnWhenScreenOn; |
Nick Pelly | 367f41f | 2011-03-08 11:43:30 -0800 | [diff] [blame] | 184 | } catch (RemoteException e) { |
Nick Pelly | cc9ee72 | 2011-04-26 16:38:00 -0700 | [diff] [blame] | 185 | attemptDeadServiceRecovery(e); |
Jeff Hamilton | bb951c8 | 2011-11-08 16:55:13 -0600 | [diff] [blame] | 186 | return ROUTE_OFF; |
Nick Pelly | 367f41f | 2011-03-08 11:43:30 -0800 | [diff] [blame] | 187 | } |
| 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 Hamilton | bb951c8 | 2011-11-08 16:55:13 -0600 | [diff] [blame] | 198 | * @param route a {@link CardEmulationRoute} |
Nick Pelly | 367f41f | 2011-03-08 11:43:30 -0800 | [diff] [blame] | 199 | */ |
| 200 | public void setCardEmulationRoute(CardEmulationRoute route) { |
| 201 | try { |
Jeff Hamilton | bb951c8 | 2011-11-08 16:55:13 -0600 | [diff] [blame] | 202 | sService.setCardEmulationRoute(mPackageName, route.route); |
Nick Pelly | 367f41f | 2011-03-08 11:43:30 -0800 | [diff] [blame] | 203 | } catch (RemoteException e) { |
Nick Pelly | cc9ee72 | 2011-04-26 16:38:00 -0700 | [diff] [blame] | 204 | attemptDeadServiceRecovery(e); |
Nick Pelly | 367f41f | 2011-03-08 11:43:30 -0800 | [diff] [blame] | 205 | } |
| 206 | } |
| 207 | |
| 208 | /** |
| 209 | * Get the {@link NfcExecutionEnvironment} that is embedded with the |
Jeff Hamilton | bb951c8 | 2011-11-08 16:55:13 -0600 | [diff] [blame] | 210 | * {@link NfcAdapter}. |
Nick Pelly | 367f41f | 2011-03-08 11:43:30 -0800 | [diff] [blame] | 211 | * |
| 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 Hamilton | bb951c8 | 2011-11-08 16:55:13 -0600 | [diff] [blame] | 218 | return mEmbeddedEe; |
Nick Pelly | 367f41f | 2011-03-08 11:43:30 -0800 | [diff] [blame] | 219 | } |
Jason parks | ab8f48c | 2011-03-31 13:15:18 -0500 | [diff] [blame] | 220 | |
Nick Pelly | 17523ab | 2011-06-17 10:56:39 -0700 | [diff] [blame] | 221 | /** |
| 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 Hamilton | bb951c8 | 2011-11-08 16:55:13 -0600 | [diff] [blame] | 227 | * @param token a implementation specific token |
| 228 | * @throws java.lang.SecurityException if authentication failed |
Nick Pelly | 17523ab | 2011-06-17 10:56:39 -0700 | [diff] [blame] | 229 | */ |
| 230 | public void authenticate(byte[] token) { |
Jason parks | ab8f48c | 2011-03-31 13:15:18 -0500 | [diff] [blame] | 231 | try { |
Jeff Hamilton | bb951c8 | 2011-11-08 16:55:13 -0600 | [diff] [blame] | 232 | sService.authenticate(mPackageName, token); |
Jason parks | ab8f48c | 2011-03-31 13:15:18 -0500 | [diff] [blame] | 233 | } catch (RemoteException e) { |
Nick Pelly | cc9ee72 | 2011-04-26 16:38:00 -0700 | [diff] [blame] | 234 | attemptDeadServiceRecovery(e); |
Jason parks | ab8f48c | 2011-03-31 13:15:18 -0500 | [diff] [blame] | 235 | } |
| 236 | } |
mike wakerly | f74df47 | 2012-10-03 13:45:00 -0700 | [diff] [blame] | 237 | |
| 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 Pelly | 367f41f | 2011-03-08 11:43:30 -0800 | [diff] [blame] | 254 | } |