Merge "Implementation of HCE for NFC-F."
am: e168012ff2
* commit 'e168012ff21408f8be85040bb4ac977061519f62':
Implementation of HCE for NFC-F.
This commit is contained in:
@ -202,6 +202,7 @@ LOCAL_SRC_FILES += \
|
||||
core/java/android/nfc/INfcAdapterExtras.aidl \
|
||||
core/java/android/nfc/INfcTag.aidl \
|
||||
core/java/android/nfc/INfcCardEmulation.aidl \
|
||||
core/java/android/nfc/INfcFCardEmulation.aidl \
|
||||
core/java/android/nfc/INfcUnlockHandler.aidl \
|
||||
core/java/android/os/IBatteryPropertiesListener.aidl \
|
||||
core/java/android/os/IBatteryPropertiesRegistrar.aidl \
|
||||
|
@ -9336,6 +9336,7 @@ package android.content.pm {
|
||||
field public static final java.lang.String FEATURE_MIDI = "android.software.midi";
|
||||
field public static final java.lang.String FEATURE_NFC = "android.hardware.nfc";
|
||||
field public static final java.lang.String FEATURE_NFC_HOST_CARD_EMULATION = "android.hardware.nfc.hce";
|
||||
field public static final java.lang.String FEATURE_NFC_HOST_CARD_EMULATION_NFCF = "android.hardware.nfc.hcef";
|
||||
field public static final java.lang.String FEATURE_OPENGLES_EXTENSION_PACK = "android.hardware.opengles.aep";
|
||||
field public static final java.lang.String FEATURE_PRINTING = "android.software.print";
|
||||
field public static final java.lang.String FEATURE_SCREEN_LANDSCAPE = "android.hardware.screen.landscape";
|
||||
@ -23866,6 +23867,28 @@ package android.nfc.cardemulation {
|
||||
field public static final java.lang.String SERVICE_META_DATA = "android.nfc.cardemulation.host_apdu_service";
|
||||
}
|
||||
|
||||
public abstract class HostNfcFService extends android.app.Service {
|
||||
ctor public HostNfcFService();
|
||||
method public final android.os.IBinder onBind(android.content.Intent);
|
||||
method public abstract void onDeactivated(int);
|
||||
method public abstract byte[] processNfcFPacket(byte[], android.os.Bundle);
|
||||
method public final void sendResponsePacket(byte[]);
|
||||
field public static final int DEACTIVATION_LINK_LOSS = 0; // 0x0
|
||||
field public static final java.lang.String SERVICE_INTERFACE = "android.nfc.cardemulation.action.HOST_NFCF_SERVICE";
|
||||
field public static final java.lang.String SERVICE_META_DATA = "android.nfc.cardemulation.host_nfcf_service";
|
||||
}
|
||||
|
||||
public final class NfcFCardEmulation {
|
||||
method public boolean disableNfcFForegroundService(android.app.Activity);
|
||||
method public boolean enableNfcFForegroundService(android.app.Activity, android.content.ComponentName);
|
||||
method public static synchronized android.nfc.cardemulation.NfcFCardEmulation getInstance(android.nfc.NfcAdapter);
|
||||
method public java.lang.String getNfcid2ForService(android.content.ComponentName);
|
||||
method public java.lang.String getSystemCodeForService(android.content.ComponentName);
|
||||
method public boolean registerSystemCodeForService(android.content.ComponentName, java.lang.String);
|
||||
method public boolean removeSystemCodeForService(android.content.ComponentName);
|
||||
method public boolean setNfcid2ForService(android.content.ComponentName, java.lang.String);
|
||||
}
|
||||
|
||||
public abstract class OffHostApduService extends android.app.Service {
|
||||
ctor public OffHostApduService();
|
||||
method public abstract android.os.IBinder onBind(android.content.Intent);
|
||||
|
@ -9630,6 +9630,7 @@ package android.content.pm {
|
||||
field public static final java.lang.String FEATURE_MIDI = "android.software.midi";
|
||||
field public static final java.lang.String FEATURE_NFC = "android.hardware.nfc";
|
||||
field public static final java.lang.String FEATURE_NFC_HOST_CARD_EMULATION = "android.hardware.nfc.hce";
|
||||
field public static final java.lang.String FEATURE_NFC_HOST_CARD_EMULATION_NFCF = "android.hardware.nfc.hcef";
|
||||
field public static final java.lang.String FEATURE_OPENGLES_EXTENSION_PACK = "android.hardware.opengles.aep";
|
||||
field public static final java.lang.String FEATURE_PRINTING = "android.software.print";
|
||||
field public static final java.lang.String FEATURE_SCREEN_LANDSCAPE = "android.hardware.screen.landscape";
|
||||
@ -25811,6 +25812,28 @@ package android.nfc.cardemulation {
|
||||
field public static final java.lang.String SERVICE_META_DATA = "android.nfc.cardemulation.host_apdu_service";
|
||||
}
|
||||
|
||||
public abstract class HostNfcFService extends android.app.Service {
|
||||
ctor public HostNfcFService();
|
||||
method public final android.os.IBinder onBind(android.content.Intent);
|
||||
method public abstract void onDeactivated(int);
|
||||
method public abstract byte[] processNfcFPacket(byte[], android.os.Bundle);
|
||||
method public final void sendResponsePacket(byte[]);
|
||||
field public static final int DEACTIVATION_LINK_LOSS = 0; // 0x0
|
||||
field public static final java.lang.String SERVICE_INTERFACE = "android.nfc.cardemulation.action.HOST_NFCF_SERVICE";
|
||||
field public static final java.lang.String SERVICE_META_DATA = "android.nfc.cardemulation.host_nfcf_service";
|
||||
}
|
||||
|
||||
public final class NfcFCardEmulation {
|
||||
method public boolean disableNfcFForegroundService(android.app.Activity);
|
||||
method public boolean enableNfcFForegroundService(android.app.Activity, android.content.ComponentName);
|
||||
method public static synchronized android.nfc.cardemulation.NfcFCardEmulation getInstance(android.nfc.NfcAdapter);
|
||||
method public java.lang.String getNfcid2ForService(android.content.ComponentName);
|
||||
method public java.lang.String getSystemCodeForService(android.content.ComponentName);
|
||||
method public boolean registerSystemCodeForService(android.content.ComponentName, java.lang.String);
|
||||
method public boolean removeSystemCodeForService(android.content.ComponentName);
|
||||
method public boolean setNfcid2ForService(android.content.ComponentName, java.lang.String);
|
||||
}
|
||||
|
||||
public abstract class OffHostApduService extends android.app.Service {
|
||||
ctor public OffHostApduService();
|
||||
method public abstract android.os.IBinder onBind(android.content.Intent);
|
||||
|
@ -1293,6 +1293,14 @@ public abstract class PackageManager {
|
||||
@SdkConstant(SdkConstantType.FEATURE)
|
||||
public static final String FEATURE_NFC_HOST_CARD_EMULATION = "android.hardware.nfc.hce";
|
||||
|
||||
/**
|
||||
* Feature for {@link #getSystemAvailableFeatures} and
|
||||
* {@link #hasSystemFeature}: The device supports host-
|
||||
* based NFC-F card emulation.
|
||||
*/
|
||||
@SdkConstant(SdkConstantType.FEATURE)
|
||||
public static final String FEATURE_NFC_HOST_CARD_EMULATION_NFCF = "android.hardware.nfc.hcef";
|
||||
|
||||
/**
|
||||
* Feature for {@link #getSystemAvailableFeatures} and
|
||||
* {@link #hasSystemFeature}: The device supports the OpenGL ES
|
||||
|
@ -26,6 +26,7 @@ import android.nfc.IAppCallback;
|
||||
import android.nfc.INfcAdapterExtras;
|
||||
import android.nfc.INfcTag;
|
||||
import android.nfc.INfcCardEmulation;
|
||||
import android.nfc.INfcFCardEmulation;
|
||||
import android.nfc.INfcUnlockHandler;
|
||||
import android.os.Bundle;
|
||||
|
||||
@ -36,6 +37,7 @@ interface INfcAdapter
|
||||
{
|
||||
INfcTag getNfcTagInterface();
|
||||
INfcCardEmulation getNfcCardEmulationInterface();
|
||||
INfcFCardEmulation getNfcFCardEmulationInterface();
|
||||
INfcAdapterExtras getNfcAdapterExtrasInterface(in String pkg);
|
||||
|
||||
int getState();
|
||||
|
36
core/java/android/nfc/INfcFCardEmulation.aidl
Normal file
36
core/java/android/nfc/INfcFCardEmulation.aidl
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.nfc;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.nfc.cardemulation.NfcFServiceInfo;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
interface INfcFCardEmulation
|
||||
{
|
||||
String getSystemCodeForService(int userHandle, in ComponentName service);
|
||||
boolean registerSystemCodeForService(int userHandle, in ComponentName service, String systemCode);
|
||||
boolean removeSystemCodeForService(int userHandle, in ComponentName service);
|
||||
String getNfcid2ForService(int userHandle, in ComponentName service);
|
||||
boolean setNfcid2ForService(int userHandle, in ComponentName service, String nfcid2);
|
||||
boolean enableNfcFForegroundService(in ComponentName service);
|
||||
boolean disableNfcFForegroundService();
|
||||
List<NfcFServiceInfo> getNfcFServices(int userHandle);
|
||||
int getMaxNumOfRegisterableSystemCodes();
|
||||
}
|
@ -294,6 +294,7 @@ public final class NfcAdapter {
|
||||
static INfcAdapter sService;
|
||||
static INfcTag sTagService;
|
||||
static INfcCardEmulation sCardEmulationService;
|
||||
static INfcFCardEmulation sNfcFCardEmulationService;
|
||||
|
||||
/**
|
||||
* The NfcAdapter object for each application context.
|
||||
@ -452,6 +453,13 @@ public final class NfcAdapter {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
try {
|
||||
sNfcFCardEmulationService = sService.getNfcFCardEmulationInterface();
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "could not retrieve NFC-F card emulation service");
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
sIsInitialized = true;
|
||||
}
|
||||
if (context == null) {
|
||||
@ -570,6 +578,15 @@ public final class NfcAdapter {
|
||||
return sCardEmulationService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the binder interface to the NFC-F card emulation service.
|
||||
* @hide
|
||||
*/
|
||||
public INfcFCardEmulation getNfcFCardEmulationService() {
|
||||
isEnabled();
|
||||
return sNfcFCardEmulationService;
|
||||
}
|
||||
|
||||
/**
|
||||
* NFC service dead - attempt best effort recovery
|
||||
* @hide
|
||||
@ -601,6 +618,12 @@ public final class NfcAdapter {
|
||||
Log.e(TAG, "could not retrieve NFC card emulation service during service recovery");
|
||||
}
|
||||
|
||||
try {
|
||||
sNfcFCardEmulationService = service.getNfcFCardEmulationInterface();
|
||||
} catch (RemoteException ee) {
|
||||
Log.e(TAG, "could not retrieve NFC-F card emulation service during service recovery");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
210
core/java/android/nfc/cardemulation/HostNfcFService.java
Normal file
210
core/java/android/nfc/cardemulation/HostNfcFService.java
Normal file
@ -0,0 +1,210 @@
|
||||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.nfc.cardemulation;
|
||||
|
||||
import android.annotation.SdkConstant;
|
||||
import android.annotation.SdkConstant.SdkConstantType;
|
||||
import android.app.Service;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Message;
|
||||
import android.os.Messenger;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* <p>HostNfcFService is a convenience {@link Service} class that can be
|
||||
* extended to emulate an NFC-F card inside an Android service component.
|
||||
*/
|
||||
public abstract class HostNfcFService extends Service {
|
||||
/**
|
||||
* The {@link Intent} action that must be declared as handled by the service.
|
||||
*/
|
||||
@SdkConstant(SdkConstantType.SERVICE_ACTION)
|
||||
public static final String SERVICE_INTERFACE =
|
||||
"android.nfc.cardemulation.action.HOST_NFCF_SERVICE";
|
||||
|
||||
/**
|
||||
* The name of the meta-data element that contains
|
||||
* more information about this service.
|
||||
*/
|
||||
public static final String SERVICE_META_DATA =
|
||||
"android.nfc.cardemulation.host_nfcf_service";
|
||||
|
||||
/**
|
||||
* Reason for {@link #onDeactivated(int)}.
|
||||
* Indicates deactivation was due to the NFC link
|
||||
* being lost.
|
||||
*/
|
||||
public static final int DEACTIVATION_LINK_LOSS = 0;
|
||||
|
||||
static final String TAG = "NfcFService";
|
||||
|
||||
/**
|
||||
* MSG_COMMAND_PACKET is sent by NfcService when
|
||||
* a NFC-F command packet has been received.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static final int MSG_COMMAND_PACKET = 0;
|
||||
|
||||
/**
|
||||
* MSG_RESPONSE_PACKET is sent to NfcService to send
|
||||
* a response packet back to the remote device.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static final int MSG_RESPONSE_PACKET = 1;
|
||||
|
||||
/**
|
||||
* MSG_DEACTIVATED is sent by NfcService when
|
||||
* the current session is finished; because
|
||||
* the NFC link was deactivated.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static final int MSG_DEACTIVATED = 2;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static final String KEY_DATA = "data";
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static final String KEY_MESSENGER = "messenger";
|
||||
|
||||
/**
|
||||
* Messenger interface to NfcService for sending responses.
|
||||
* Only accessed on main thread by the message handler.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
Messenger mNfcService = null;
|
||||
|
||||
final Messenger mMessenger = new Messenger(new MsgHandler());
|
||||
|
||||
final class MsgHandler extends Handler {
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case MSG_COMMAND_PACKET:
|
||||
Bundle dataBundle = msg.getData();
|
||||
if (dataBundle == null) {
|
||||
return;
|
||||
}
|
||||
if (mNfcService == null) mNfcService = msg.replyTo;
|
||||
|
||||
byte[] packet = dataBundle.getByteArray(KEY_DATA);
|
||||
if (packet != null) {
|
||||
byte[] responsePacket = processNfcFPacket(packet, null);
|
||||
if (responsePacket != null) {
|
||||
if (mNfcService == null) {
|
||||
Log.e(TAG, "Response not sent; service was deactivated.");
|
||||
return;
|
||||
}
|
||||
Message responseMsg = Message.obtain(null, MSG_RESPONSE_PACKET);
|
||||
Bundle responseBundle = new Bundle();
|
||||
responseBundle.putByteArray(KEY_DATA, responsePacket);
|
||||
responseMsg.setData(responseBundle);
|
||||
responseMsg.replyTo = mMessenger;
|
||||
try {
|
||||
mNfcService.send(responseMsg);
|
||||
} catch (RemoteException e) {
|
||||
Log.e("TAG", "Response not sent; RemoteException calling into " +
|
||||
"NfcService.");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Log.e(TAG, "Received MSG_COMMAND_PACKET without data.");
|
||||
}
|
||||
break;
|
||||
case MSG_RESPONSE_PACKET:
|
||||
if (mNfcService == null) {
|
||||
Log.e(TAG, "Response not sent; service was deactivated.");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
msg.replyTo = mMessenger;
|
||||
mNfcService.send(msg);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "RemoteException calling into NfcService.");
|
||||
}
|
||||
break;
|
||||
case MSG_DEACTIVATED:
|
||||
// Make sure we won't call into NfcService again
|
||||
mNfcService = null;
|
||||
onDeactivated(msg.arg1);
|
||||
break;
|
||||
default:
|
||||
super.handleMessage(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final IBinder onBind(Intent intent) {
|
||||
return mMessenger.getBinder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a response packet back to the remote device.
|
||||
*
|
||||
* <p>Note: this method may be called from any thread and will not block.
|
||||
* @param responsePacket A byte-array containing the response packet.
|
||||
*/
|
||||
public final void sendResponsePacket(byte[] responsePacket) {
|
||||
Message responseMsg = Message.obtain(null, MSG_RESPONSE_PACKET);
|
||||
Bundle dataBundle = new Bundle();
|
||||
dataBundle.putByteArray(KEY_DATA, responsePacket);
|
||||
responseMsg.setData(dataBundle);
|
||||
try {
|
||||
mMessenger.send(responseMsg);
|
||||
} catch (RemoteException e) {
|
||||
Log.e("TAG", "Local messenger has died.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>This method will be called when a NFC-F packet has been received
|
||||
* from a remote device. A response packet can be provided directly
|
||||
* by returning a byte-array in this method. Note that in general
|
||||
* response packets must be sent as quickly as possible, given the fact
|
||||
* that the user is likely holding his device over an NFC reader
|
||||
* when this method is called.
|
||||
*
|
||||
* <p class="note">This method is running on the main thread of your application.
|
||||
* If you cannot return a response packet immediately, return null
|
||||
* and use the {@link #sendResponsePacket(byte[])} method later.
|
||||
*
|
||||
* @param commandPacket The NFC-F packet that was received from the remote device
|
||||
* @param extras A bundle containing extra data. May be null.
|
||||
* @return a byte-array containing the response packet, or null if no
|
||||
* response packet can be sent at this point.
|
||||
*/
|
||||
public abstract byte[] processNfcFPacket(byte[] commandPacket, Bundle extras);
|
||||
|
||||
/**
|
||||
* This method will be called in following possible scenarios:
|
||||
* <li>The NFC link has been lost
|
||||
* @param reason {@link #DEACTIVATION_LINK_LOSS}
|
||||
*/
|
||||
public abstract void onDeactivated(int reason);
|
||||
}
|
470
core/java/android/nfc/cardemulation/NfcFCardEmulation.java
Normal file
470
core/java/android/nfc/cardemulation/NfcFCardEmulation.java
Normal file
@ -0,0 +1,470 @@
|
||||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.nfc.cardemulation;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ActivityThread;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.pm.IPackageManager;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.nfc.INfcFCardEmulation;
|
||||
import android.nfc.NfcAdapter;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserHandle;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This class can be used to query the state of
|
||||
* NFC-F card emulation services.
|
||||
*
|
||||
* For a general introduction into NFC card emulation,
|
||||
* please read the <a href="{@docRoot}guide/topics/connectivity/nfc/hce.html">
|
||||
* NFC card emulation developer guide</a>.</p>
|
||||
*
|
||||
* <p class="note">Use of this class requires the
|
||||
* {@link PackageManager#FEATURE_NFC_HOST_CARD_EMULATION_NFCF}
|
||||
* to be present on the device.
|
||||
*/
|
||||
public final class NfcFCardEmulation {
|
||||
static final String TAG = "NfcFCardEmulation";
|
||||
|
||||
static boolean sIsInitialized = false;
|
||||
static HashMap<Context, NfcFCardEmulation> sCardEmus = new HashMap<Context, NfcFCardEmulation>();
|
||||
static INfcFCardEmulation sService;
|
||||
|
||||
final Context mContext;
|
||||
|
||||
private NfcFCardEmulation(Context context, INfcFCardEmulation service) {
|
||||
mContext = context.getApplicationContext();
|
||||
sService = service;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to get an instance of this class.
|
||||
*
|
||||
* @param adapter A reference to an NfcAdapter object.
|
||||
* @return
|
||||
*/
|
||||
public static synchronized NfcFCardEmulation getInstance(NfcAdapter adapter) {
|
||||
if (adapter == null) throw new NullPointerException("NfcAdapter is null");
|
||||
Context context = adapter.getContext();
|
||||
if (context == null) {
|
||||
Log.e(TAG, "NfcAdapter context is null.");
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
if (!sIsInitialized) {
|
||||
IPackageManager pm = ActivityThread.getPackageManager();
|
||||
if (pm == null) {
|
||||
Log.e(TAG, "Cannot get PackageManager");
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
try {
|
||||
if (!pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION_NFCF)) {
|
||||
Log.e(TAG, "This device does not support NFC-F card emulation");
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "PackageManager query failed.");
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
sIsInitialized = true;
|
||||
}
|
||||
NfcFCardEmulation manager = sCardEmus.get(context);
|
||||
if (manager == null) {
|
||||
// Get card emu service
|
||||
INfcFCardEmulation service = adapter.getNfcFCardEmulationService();
|
||||
if (service == null) {
|
||||
Log.e(TAG, "This device does not implement the INfcFCardEmulation interface.");
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
manager = new NfcFCardEmulation(context, service);
|
||||
sCardEmus.put(context, manager);
|
||||
}
|
||||
return manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the current System Code for the specified service.
|
||||
*
|
||||
* <p>Before calling {@link #registerSystemCodeForService(ComponentName, String)},
|
||||
* the System Code contained in the Manifest file is returned. After calling
|
||||
* {@link #registerSystemCodeForService(ComponentName, String)}, the System Code
|
||||
* registered there is returned. After calling
|
||||
* {@link #removeSystemCodeForService(ComponentName)}, "null" is returned.
|
||||
*
|
||||
* @param service The component name of the service
|
||||
* @return the current System Code
|
||||
*/
|
||||
public String getSystemCodeForService(ComponentName service) {
|
||||
if (service == null) {
|
||||
throw new NullPointerException("service is null");
|
||||
}
|
||||
try {
|
||||
return sService.getSystemCodeForService(UserHandle.myUserId(), service);
|
||||
} catch (RemoteException e) {
|
||||
// Try one more time
|
||||
recoverService();
|
||||
if (sService == null) {
|
||||
Log.e(TAG, "Failed to recover CardEmulationService.");
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return sService.getSystemCodeForService(UserHandle.myUserId(), service);
|
||||
} catch (RemoteException ee) {
|
||||
Log.e(TAG, "Failed to reach CardEmulationService.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a System Code for the specified service.
|
||||
*
|
||||
* <p>The System Code must be in range from "4000" to "4FFF" (excluding "4*FF").
|
||||
*
|
||||
* <p>If a System Code was previously registered for this service
|
||||
* (either statically through the manifest, or dynamically by using this API),
|
||||
* it will be replaced with this one.
|
||||
*
|
||||
* <p>Even if the same System Code is already registered for another service,
|
||||
* this method succeeds in registering the System Code.
|
||||
*
|
||||
* <p>Note that you can only register a System Code for a service that
|
||||
* is running under the same UID as the caller of this API. Typically
|
||||
* this means you need to call this from the same
|
||||
* package as the service itself, though UIDs can also
|
||||
* be shared between packages using shared UIDs.
|
||||
*
|
||||
* @param service The component name of the service
|
||||
* @param systemCode The System Code to be registered
|
||||
* @return whether the registration was successful.
|
||||
*/
|
||||
public boolean registerSystemCodeForService(ComponentName service, String systemCode) {
|
||||
if (service == null || systemCode == null) {
|
||||
throw new NullPointerException("service or systemCode is null");
|
||||
}
|
||||
try {
|
||||
return sService.registerSystemCodeForService(UserHandle.myUserId(),
|
||||
service, systemCode);
|
||||
} catch (RemoteException e) {
|
||||
// Try one more time
|
||||
recoverService();
|
||||
if (sService == null) {
|
||||
Log.e(TAG, "Failed to recover CardEmulationService.");
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
return sService.registerSystemCodeForService(UserHandle.myUserId(),
|
||||
service, systemCode);
|
||||
} catch (RemoteException ee) {
|
||||
Log.e(TAG, "Failed to reach CardEmulationService.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a registered System Code for the specified service.
|
||||
*
|
||||
* @param service The component name of the service
|
||||
* @return whether the System Code was successfully removed.
|
||||
*/
|
||||
public boolean removeSystemCodeForService(ComponentName service) {
|
||||
if (service == null) {
|
||||
throw new NullPointerException("service is null");
|
||||
}
|
||||
try {
|
||||
return sService.removeSystemCodeForService(UserHandle.myUserId(), service);
|
||||
} catch (RemoteException e) {
|
||||
// Try one more time
|
||||
recoverService();
|
||||
if (sService == null) {
|
||||
Log.e(TAG, "Failed to recover CardEmulationService.");
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
return sService.removeSystemCodeForService(UserHandle.myUserId(), service);
|
||||
} catch (RemoteException ee) {
|
||||
Log.e(TAG, "Failed to reach CardEmulationService.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the current NFCID2 for the specified service.
|
||||
*
|
||||
* <p>Before calling {@link #setNfcid2ForService(ComponentName, String)},
|
||||
* the NFCID2 contained in the Manifest file is returned. If "random" is specified
|
||||
* in the Manifest file, a random number assigned by the system at installation time
|
||||
* is returned. After setting an NFCID2
|
||||
* with {@link #setNfcid2ForService(ComponentName, String)}, this NFCID2 is returned.
|
||||
*
|
||||
* @param service The component name of the service
|
||||
* @return the current NFCID2
|
||||
*/
|
||||
public String getNfcid2ForService(ComponentName service) {
|
||||
if (service == null) {
|
||||
throw new NullPointerException("service is null");
|
||||
}
|
||||
try {
|
||||
return sService.getNfcid2ForService(UserHandle.myUserId(), service);
|
||||
} catch (RemoteException e) {
|
||||
// Try one more time
|
||||
recoverService();
|
||||
if (sService == null) {
|
||||
Log.e(TAG, "Failed to recover CardEmulationService.");
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return sService.getNfcid2ForService(UserHandle.myUserId(), service);
|
||||
} catch (RemoteException ee) {
|
||||
Log.e(TAG, "Failed to reach CardEmulationService.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a NFCID2 for the specified service.
|
||||
*
|
||||
* <p>The NFCID2 must be in range from "02FE000000000000" to "02FEFFFFFFFFFFFF".
|
||||
*
|
||||
* <p>If a NFCID2 was previously set for this service
|
||||
* (either statically through the manifest, or dynamically by using this API),
|
||||
* it will be replaced.
|
||||
*
|
||||
* <p>Note that you can only set the NFCID2 for a service that
|
||||
* is running under the same UID as the caller of this API. Typically
|
||||
* this means you need to call this from the same
|
||||
* package as the service itself, though UIDs can also
|
||||
* be shared between packages using shared UIDs.
|
||||
*
|
||||
* @param service The component name of the service
|
||||
* @param nfcid2 The NFCID2 to be registered
|
||||
* @return whether the setting was successful.
|
||||
*/
|
||||
public boolean setNfcid2ForService(ComponentName service, String nfcid2) {
|
||||
if (service == null || nfcid2 == null) {
|
||||
throw new NullPointerException("service or nfcid2 is null");
|
||||
}
|
||||
try {
|
||||
return sService.setNfcid2ForService(UserHandle.myUserId(),
|
||||
service, nfcid2);
|
||||
} catch (RemoteException e) {
|
||||
// Try one more time
|
||||
recoverService();
|
||||
if (sService == null) {
|
||||
Log.e(TAG, "Failed to recover CardEmulationService.");
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
return sService.setNfcid2ForService(UserHandle.myUserId(),
|
||||
service, nfcid2);
|
||||
} catch (RemoteException ee) {
|
||||
Log.e(TAG, "Failed to reach CardEmulationService.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows a foreground application to specify which card emulation service
|
||||
* should be enabled while a specific Activity is in the foreground.
|
||||
*
|
||||
* <p>The specified HCE-F service is only enabled when the corresponding application is
|
||||
* in the foreground and this method has been called. When the application is moved to
|
||||
* the background, {@link #disableNfcFForegroundService(Activity)} is called, or
|
||||
* NFCID2 or System Code is replaced, the HCE-F service is disabled.
|
||||
*
|
||||
* <p>The specified Activity must currently be in resumed state. A good
|
||||
* paradigm is to call this method in your {@link Activity#onResume}, and to call
|
||||
* {@link #disableNfcFForegroundService(Activity)} in your {@link Activity#onPause}.
|
||||
*
|
||||
* <p>Note that this preference is not persisted by the OS, and hence must be
|
||||
* called every time the Activity is resumed.
|
||||
*
|
||||
* @param activity The activity which prefers this service to be invoked
|
||||
* @param service The service to be preferred while this activity is in the foreground
|
||||
* @return whether the registration was successful
|
||||
*/
|
||||
public boolean enableNfcFForegroundService(Activity activity, ComponentName service) {
|
||||
if (activity == null || service == null) {
|
||||
throw new NullPointerException("activity or service is null");
|
||||
}
|
||||
// Verify the activity is in the foreground before calling into NfcService
|
||||
if (!activity.isResumed()) {
|
||||
throw new IllegalArgumentException("Activity must be resumed.");
|
||||
}
|
||||
try {
|
||||
return sService.enableNfcFForegroundService(service);
|
||||
} catch (RemoteException e) {
|
||||
// Try one more time
|
||||
recoverService();
|
||||
if (sService == null) {
|
||||
Log.e(TAG, "Failed to recover CardEmulationService.");
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
return sService.enableNfcFForegroundService(service);
|
||||
} catch (RemoteException ee) {
|
||||
Log.e(TAG, "Failed to reach CardEmulationService.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables the service for the specified Activity.
|
||||
*
|
||||
* <p>Note that the specified Activity must still be in resumed
|
||||
* state at the time of this call. A good place to call this method
|
||||
* is in your {@link Activity#onPause} implementation.
|
||||
*
|
||||
* @param activity The activity which the service was registered for
|
||||
* @return true when successful
|
||||
*/
|
||||
public boolean disableNfcFForegroundService(Activity activity) {
|
||||
if (activity == null) {
|
||||
throw new NullPointerException("activity is null");
|
||||
}
|
||||
if (!activity.isResumed()) {
|
||||
throw new IllegalArgumentException("Activity must be resumed.");
|
||||
}
|
||||
try {
|
||||
return sService.disableNfcFForegroundService();
|
||||
} catch (RemoteException e) {
|
||||
// Try one more time
|
||||
recoverService();
|
||||
if (sService == null) {
|
||||
Log.e(TAG, "Failed to recover CardEmulationService.");
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
return sService.disableNfcFForegroundService();
|
||||
} catch (RemoteException ee) {
|
||||
Log.e(TAG, "Failed to reach CardEmulationService.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public List<NfcFServiceInfo> getNfcFServices() {
|
||||
try {
|
||||
return sService.getNfcFServices(UserHandle.myUserId());
|
||||
} catch (RemoteException e) {
|
||||
// Try one more time
|
||||
recoverService();
|
||||
if (sService == null) {
|
||||
Log.e(TAG, "Failed to recover CardEmulationService.");
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return sService.getNfcFServices(UserHandle.myUserId());
|
||||
} catch (RemoteException ee) {
|
||||
Log.e(TAG, "Failed to reach CardEmulationService.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public int getMaxNumOfRegisterableSystemCodes() {
|
||||
try {
|
||||
return sService.getMaxNumOfRegisterableSystemCodes();
|
||||
} catch (RemoteException e) {
|
||||
// Try one more time
|
||||
recoverService();
|
||||
if (sService == null) {
|
||||
Log.e(TAG, "Failed to recover CardEmulationService.");
|
||||
return -1;
|
||||
}
|
||||
try {
|
||||
return sService.getMaxNumOfRegisterableSystemCodes();
|
||||
} catch (RemoteException ee) {
|
||||
Log.e(TAG, "Failed to reach CardEmulationService.");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static boolean isValidSystemCode(String systemCode) {
|
||||
if (systemCode == null) {
|
||||
return false;
|
||||
}
|
||||
if (systemCode.length() != 4) {
|
||||
Log.e(TAG, "System Code " + systemCode + " is not a valid System Code.");
|
||||
return false;
|
||||
}
|
||||
// check if the value is between "4000" and "4FFF" (excluding "4*FF")
|
||||
if (!systemCode.startsWith("4") || systemCode.toUpperCase().endsWith("FF")) {
|
||||
Log.e(TAG, "System Code " + systemCode + " is not a valid System Code.");
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
Integer.valueOf(systemCode, 16);
|
||||
} catch (NumberFormatException e) {
|
||||
Log.e(TAG, "System Code " + systemCode + " is not a valid System Code.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static boolean isValidNfcid2(String nfcid2) {
|
||||
if (nfcid2 == null) {
|
||||
return false;
|
||||
}
|
||||
if (nfcid2.length() != 16) {
|
||||
Log.e(TAG, "NFCID2 " + nfcid2 + " is not a valid NFCID2.");
|
||||
return false;
|
||||
}
|
||||
// check if the the value starts with "02FE"
|
||||
if (!nfcid2.toUpperCase().startsWith("02FE")) {
|
||||
Log.e(TAG, "NFCID2 " + nfcid2 + " is not a valid NFCID2.");
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
Long.valueOf(nfcid2, 16);
|
||||
} catch (NumberFormatException e) {
|
||||
Log.e(TAG, "NFCID2 " + nfcid2 + " is not a valid NFCID2.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void recoverService() {
|
||||
NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext);
|
||||
sService = adapter.getNfcFCardEmulationService();
|
||||
}
|
||||
|
||||
}
|
||||
|
19
core/java/android/nfc/cardemulation/NfcFServiceInfo.aidl
Normal file
19
core/java/android/nfc/cardemulation/NfcFServiceInfo.aidl
Normal file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.nfc.cardemulation;
|
||||
|
||||
parcelable NfcFServiceInfo;
|
304
core/java/android/nfc/cardemulation/NfcFServiceInfo.java
Normal file
304
core/java/android/nfc/cardemulation/NfcFServiceInfo.java
Normal file
@ -0,0 +1,304 @@
|
||||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.nfc.cardemulation;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.TypedArray;
|
||||
import android.content.res.XmlResourceParser;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.util.Xml;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public final class NfcFServiceInfo implements Parcelable {
|
||||
static final String TAG = "NfcFServiceInfo";
|
||||
|
||||
/**
|
||||
* The service that implements this
|
||||
*/
|
||||
final ResolveInfo mService;
|
||||
|
||||
/**
|
||||
* Description of the service
|
||||
*/
|
||||
final String mDescription;
|
||||
|
||||
/**
|
||||
* System Code of the service
|
||||
*/
|
||||
final String mSystemCode;
|
||||
|
||||
/**
|
||||
* System Code of the service registered by API
|
||||
*/
|
||||
String mDynamicSystemCode;
|
||||
|
||||
/**
|
||||
* NFCID2 of the service
|
||||
*/
|
||||
final String mNfcid2;
|
||||
|
||||
/**
|
||||
* NFCID2 of the service registered by API
|
||||
*/
|
||||
String mDynamicNfcid2;
|
||||
|
||||
/**
|
||||
* The uid of the package the service belongs to
|
||||
*/
|
||||
final int mUid;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public NfcFServiceInfo(ResolveInfo info, String description,
|
||||
String systemCode, String dynamicSystemCode, String nfcid2, String dynamicNfcid2,
|
||||
int uid) {
|
||||
this.mService = info;
|
||||
this.mDescription = description;
|
||||
this.mSystemCode = systemCode;
|
||||
this.mDynamicSystemCode = dynamicSystemCode;
|
||||
this.mNfcid2 = nfcid2;
|
||||
this.mDynamicNfcid2 = dynamicNfcid2;
|
||||
this.mUid = uid;
|
||||
}
|
||||
|
||||
public NfcFServiceInfo(PackageManager pm, ResolveInfo info)
|
||||
throws XmlPullParserException, IOException {
|
||||
ServiceInfo si = info.serviceInfo;
|
||||
XmlResourceParser parser = null;
|
||||
try {
|
||||
parser = si.loadXmlMetaData(pm, HostNfcFService.SERVICE_META_DATA);
|
||||
if (parser == null) {
|
||||
throw new XmlPullParserException("No " + HostNfcFService.SERVICE_META_DATA +
|
||||
" meta-data");
|
||||
}
|
||||
|
||||
int eventType = parser.getEventType();
|
||||
while (eventType != XmlPullParser.START_TAG &&
|
||||
eventType != XmlPullParser.END_DOCUMENT) {
|
||||
eventType = parser.next();
|
||||
}
|
||||
|
||||
String tagName = parser.getName();
|
||||
if (!"host-nfcf-service".equals(tagName)) {
|
||||
throw new XmlPullParserException(
|
||||
"Meta-data does not start with <host-nfcf-service> tag");
|
||||
}
|
||||
|
||||
Resources res = pm.getResourcesForApplication(si.applicationInfo);
|
||||
AttributeSet attrs = Xml.asAttributeSet(parser);
|
||||
TypedArray sa = res.obtainAttributes(attrs,
|
||||
com.android.internal.R.styleable.HostNfcFService);
|
||||
mService = info;
|
||||
mDescription = sa.getString(
|
||||
com.android.internal.R.styleable.HostNfcFService_description);
|
||||
mDynamicSystemCode = null;
|
||||
mDynamicNfcid2 = null;
|
||||
sa.recycle();
|
||||
|
||||
String systemCode = null;
|
||||
String nfcid2 = null;
|
||||
final int depth = parser.getDepth();
|
||||
|
||||
while (((eventType = parser.next()) != XmlPullParser.END_TAG ||
|
||||
parser.getDepth() > depth) && eventType != XmlPullParser.END_DOCUMENT) {
|
||||
tagName = parser.getName();
|
||||
if (eventType == XmlPullParser.START_TAG &&
|
||||
"system-code-filter".equals(tagName) && systemCode == null) {
|
||||
final TypedArray a = res.obtainAttributes(attrs,
|
||||
com.android.internal.R.styleable.SystemCodeFilter);
|
||||
systemCode = a.getString(
|
||||
com.android.internal.R.styleable.SystemCodeFilter_name).toUpperCase();
|
||||
if (!NfcFCardEmulation.isValidSystemCode(systemCode) &&
|
||||
!systemCode.equalsIgnoreCase("NULL")) {
|
||||
Log.e(TAG, "Invalid System Code: " + systemCode);
|
||||
systemCode = null;
|
||||
}
|
||||
a.recycle();
|
||||
} else if (eventType == XmlPullParser.START_TAG &&
|
||||
"nfcid2-filter".equals(tagName) && nfcid2 == null) {
|
||||
final TypedArray a = res.obtainAttributes(attrs,
|
||||
com.android.internal.R.styleable.Nfcid2Filter);
|
||||
nfcid2 = a.getString(
|
||||
com.android.internal.R.styleable.Nfcid2Filter_name).toUpperCase();
|
||||
if (!nfcid2.equalsIgnoreCase("RANDOM") &&
|
||||
!nfcid2.equalsIgnoreCase("NULL") &&
|
||||
!NfcFCardEmulation.isValidNfcid2(nfcid2)) {
|
||||
Log.e(TAG, "Invalid NFCID2: " + nfcid2);
|
||||
nfcid2 = null;
|
||||
}
|
||||
a.recycle();
|
||||
}
|
||||
}
|
||||
mSystemCode = (systemCode == null ? "NULL" : systemCode);
|
||||
mNfcid2 = (nfcid2 == null ? "NULL" : nfcid2);
|
||||
} catch (NameNotFoundException e) {
|
||||
throw new XmlPullParserException("Unable to create context for: " + si.packageName);
|
||||
} finally {
|
||||
if (parser != null) parser.close();
|
||||
}
|
||||
// Set uid
|
||||
mUid = si.applicationInfo.uid;
|
||||
}
|
||||
|
||||
public ComponentName getComponent() {
|
||||
return new ComponentName(mService.serviceInfo.packageName,
|
||||
mService.serviceInfo.name);
|
||||
}
|
||||
|
||||
public String getSystemCode() {
|
||||
return (mDynamicSystemCode == null ? mSystemCode : mDynamicSystemCode);
|
||||
}
|
||||
|
||||
public void setOrReplaceDynamicSystemCode(String systemCode) {
|
||||
mDynamicSystemCode = systemCode;
|
||||
}
|
||||
|
||||
public String getNfcid2() {
|
||||
return (mDynamicNfcid2 == null ? mNfcid2 : mDynamicNfcid2);
|
||||
}
|
||||
|
||||
public void setOrReplaceDynamicNfcid2(String nfcid2) {
|
||||
mDynamicNfcid2 = nfcid2;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return mDescription;
|
||||
}
|
||||
|
||||
public int getUid() {
|
||||
return mUid;
|
||||
}
|
||||
|
||||
public CharSequence loadLabel(PackageManager pm) {
|
||||
return mService.loadLabel(pm);
|
||||
}
|
||||
|
||||
public Drawable loadIcon(PackageManager pm) {
|
||||
return mService.loadIcon(pm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder out = new StringBuilder("NfcFService: ");
|
||||
out.append(getComponent());
|
||||
out.append(", description: " + mDescription);
|
||||
out.append(", System Code: " + mSystemCode);
|
||||
if (mDynamicSystemCode != null) {
|
||||
out.append(", dynamic System Code: " + mDynamicSystemCode);
|
||||
}
|
||||
out.append(", NFCID2: " + mNfcid2);
|
||||
if (mDynamicNfcid2 != null) {
|
||||
out.append(", dynamic NFCID2: " + mDynamicNfcid2);
|
||||
}
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof NfcFServiceInfo)) return false;
|
||||
NfcFServiceInfo thatService = (NfcFServiceInfo) o;
|
||||
|
||||
if (!thatService.getComponent().equals(this.getComponent())) return false;
|
||||
if (!thatService.mSystemCode.equalsIgnoreCase(this.mSystemCode)) return false;
|
||||
if (!thatService.mNfcid2.equalsIgnoreCase(this.mNfcid2)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getComponent().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
mService.writeToParcel(dest, flags);
|
||||
dest.writeString(mDescription);
|
||||
dest.writeString(mSystemCode);
|
||||
dest.writeInt(mDynamicSystemCode != null ? 1 : 0);
|
||||
if (mDynamicSystemCode != null) {
|
||||
dest.writeString(mDynamicSystemCode);
|
||||
}
|
||||
dest.writeString(mNfcid2);
|
||||
dest.writeInt(mDynamicNfcid2 != null ? 1 : 0);
|
||||
if (mDynamicNfcid2 != null) {
|
||||
dest.writeString(mDynamicNfcid2);
|
||||
}
|
||||
dest.writeInt(mUid);
|
||||
};
|
||||
|
||||
public static final Parcelable.Creator<NfcFServiceInfo> CREATOR =
|
||||
new Parcelable.Creator<NfcFServiceInfo>() {
|
||||
@Override
|
||||
public NfcFServiceInfo createFromParcel(Parcel source) {
|
||||
ResolveInfo info = ResolveInfo.CREATOR.createFromParcel(source);
|
||||
String description = source.readString();
|
||||
String systemCode = source.readString();
|
||||
String dynamicSystemCode = null;
|
||||
if (source.readInt() != 0) {
|
||||
dynamicSystemCode = source.readString();
|
||||
}
|
||||
String nfcid2 = source.readString();
|
||||
String dynamicNfcid2 = null;
|
||||
if (source.readInt() != 0) {
|
||||
dynamicNfcid2 = source.readString();
|
||||
}
|
||||
int uid = source.readInt();
|
||||
NfcFServiceInfo service = new NfcFServiceInfo(info, description,
|
||||
systemCode, dynamicSystemCode, nfcid2, dynamicNfcid2, uid);
|
||||
return service;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NfcFServiceInfo[] newArray(int size) {
|
||||
return new NfcFServiceInfo[size];
|
||||
}
|
||||
};
|
||||
|
||||
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
pw.println(" " + getComponent() +
|
||||
" (Description: " + getDescription() + ")");
|
||||
pw.println(" System Code: " + getSystemCode());
|
||||
pw.println(" NFCID2: " + getNfcid2());
|
||||
}
|
||||
}
|
||||
|
@ -3315,6 +3315,32 @@ i
|
||||
<attr name="name" />
|
||||
</declare-styleable>
|
||||
|
||||
<!-- Use <code>host-nfcf-service</code> as the root tag of the XML resource that
|
||||
describes an {@link android.nfc.cardemulation.HostNfcFService} service, which
|
||||
is referenced from its {@link android.nfc.cardemulation.HostNfcFService#SERVICE_META_DATA}
|
||||
entry. -->
|
||||
<declare-styleable name="HostNfcFService">
|
||||
<!-- Short description of the functionality the service implements. This attribute
|
||||
is mandatory.-->
|
||||
<attr name="description" />
|
||||
</declare-styleable>
|
||||
|
||||
<!-- Specify one or more <code>system-code-filter</code> elements inside a
|
||||
<code>host-nfcf-service</code> element to specify a System Code
|
||||
your service can handle. -->
|
||||
<declare-styleable name="SystemCodeFilter">
|
||||
<!-- The System Code. This attribute is mandatory. -->
|
||||
<attr name="name" />
|
||||
</declare-styleable>
|
||||
|
||||
<!-- Specify one or more <code>nfcid2-filter</code> elements inside a
|
||||
<code>host-nfcf-service</code> element to specify a NFCID2
|
||||
your service can handle. -->
|
||||
<declare-styleable name="Nfcid2Filter">
|
||||
<!-- The NFCID2. This attribute is mandatory. -->
|
||||
<attr name="name" />
|
||||
</declare-styleable>
|
||||
|
||||
<declare-styleable name="ActionMenuItemView">
|
||||
<attr name="minWidth" />
|
||||
</declare-styleable>
|
||||
|
Reference in New Issue
Block a user