NfcAdapterExtras.java revision cc9ee72bd42bb40b1852f907f58305adde12ecc2
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 17package com.android.nfc_extras; 18 19import android.annotation.SdkConstant; 20import android.annotation.SdkConstant.SdkConstantType; 21import android.nfc.ApduList; 22import 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 59 // protected by NfcAdapterExtras.class, and final after first construction, 60 // except for attemptDeadServiceRecovery() when NFC crashes - we accept a 61 // best effort recovery 62 private static NfcAdapter sAdapter; 63 private static INfcAdapterExtras sService; 64 private static NfcAdapterExtras sSingleton; 65 private static NfcExecutionEnvironment sEmbeddedEe; 66 private static CardEmulationRoute sRouteOff; 67 private static CardEmulationRoute sRouteOnWhenScreenOn; 68 69 /** get service handles */ 70 private static void initService() { 71 sService = sAdapter.getNfcAdapterExtrasInterface(); 72 } 73 74 /** 75 * Get the {@link NfcAdapterExtras} for the given {@link NfcAdapter}. 76 * 77 * <p class="note"> 78 * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission. 79 * 80 * @param adapter a {@link NfcAdapter}, must not be null 81 * @return the {@link NfcAdapterExtras} object for the given {@link NfcAdapter} 82 */ 83 public static NfcAdapterExtras get(NfcAdapter adapter) { 84 synchronized(NfcAdapterExtras.class) { 85 if (sSingleton == null) { 86 try { 87 sAdapter = adapter; 88 sRouteOff = new CardEmulationRoute(CardEmulationRoute.ROUTE_OFF, null); 89 sSingleton = new NfcAdapterExtras(); 90 sEmbeddedEe = new NfcExecutionEnvironment(sSingleton); 91 sRouteOnWhenScreenOn = new CardEmulationRoute( 92 CardEmulationRoute.ROUTE_ON_WHEN_SCREEN_ON, sEmbeddedEe); 93 initService(); 94 } finally { 95 if (sSingleton == null) { 96 sService = null; 97 sEmbeddedEe = null; 98 sRouteOff = null; 99 sRouteOnWhenScreenOn = null; 100 } 101 } 102 } 103 return sSingleton; 104 } 105 } 106 107 private NfcAdapterExtras() {} 108 109 /** 110 * Immutable data class that describes a card emulation route. 111 */ 112 public final static class CardEmulationRoute { 113 /** 114 * Card Emulation is turned off on this NfcAdapter. 115 * <p>This is the default routing state after boot. 116 */ 117 public static final int ROUTE_OFF = 1; 118 119 /** 120 * Card Emulation is routed to {@link #nfcEe} only when the screen is on, 121 * otherwise it is turned off. 122 */ 123 public static final int ROUTE_ON_WHEN_SCREEN_ON = 2; 124 125 /** 126 * A route such as {@link #ROUTE_OFF} or {@link #ROUTE_ON_WHEN_SCREEN_ON}. 127 */ 128 public final int route; 129 130 /** 131 * The {@link NFcExecutionEnvironment} that is Card Emulation is routed to. 132 * <p>null if {@link #route} is {@link #ROUTE_OFF}, otherwise not null. 133 */ 134 public final NfcExecutionEnvironment nfcEe; 135 136 public CardEmulationRoute(int route, NfcExecutionEnvironment nfcEe) { 137 if (route == ROUTE_OFF && nfcEe != null) { 138 throw new IllegalArgumentException("must not specifiy a NFC-EE with ROUTE_OFF"); 139 } else if (route != ROUTE_OFF && nfcEe == null) { 140 throw new IllegalArgumentException("must specifiy a NFC-EE for this route"); 141 } 142 this.route = route; 143 this.nfcEe = nfcEe; 144 } 145 } 146 147 /** 148 * NFC service dead - attempt best effort recovery 149 */ 150 void attemptDeadServiceRecovery(Exception e) { 151 Log.e(TAG, "NFC Adapter Extras dead - attempting to recover"); 152 sAdapter.attemptDeadServiceRecovery(e); 153 initService(); 154 } 155 156 INfcAdapterExtras getService() { 157 return sService; 158 } 159 160 /** 161 * Get the routing state of this NFC EE. 162 * 163 * <p class="note"> 164 * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission. 165 * 166 * @return 167 */ 168 public CardEmulationRoute getCardEmulationRoute() { 169 try { 170 int route = sService.getCardEmulationRoute(); 171 return route == CardEmulationRoute.ROUTE_OFF ? 172 sRouteOff : 173 sRouteOnWhenScreenOn; 174 } catch (RemoteException e) { 175 attemptDeadServiceRecovery(e); 176 return sRouteOff; 177 } 178 } 179 180 /** 181 * Set the routing state of this NFC EE. 182 * 183 * <p>This routing state is not persisted across reboot. 184 * 185 * <p class="note"> 186 * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission. 187 * 188 * @param route a {@link #CardEmulationRoute} 189 */ 190 public void setCardEmulationRoute(CardEmulationRoute route) { 191 try { 192 sService.setCardEmulationRoute(route.route); 193 } catch (RemoteException e) { 194 attemptDeadServiceRecovery(e); 195 } 196 } 197 198 /** 199 * Get the {@link NfcExecutionEnvironment} that is embedded with the 200 * {@link NFcAdapter}. 201 * 202 * <p class="note"> 203 * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission. 204 * 205 * @return a {@link NfcExecutionEnvironment}, or null if there is no embedded NFC-EE 206 */ 207 public NfcExecutionEnvironment getEmbeddedExecutionEnvironment() { 208 return sEmbeddedEe; 209 } 210 211 public void registerTearDownApdus(String packageName, ApduList apdus) { 212 try { 213 sService.registerTearDownApdus(packageName, apdus); 214 } catch (RemoteException e) { 215 attemptDeadServiceRecovery(e); 216 } 217 } 218 219 public void unregisterTearDownApdus(String packageName) { 220 try { 221 sService.unregisterTearDownApdus(packageName); 222 } catch (RemoteException e) { 223 attemptDeadServiceRecovery(e); 224 } 225 } 226} 227