Merge "Add getApplicationConfigForPackage"
diff --git a/Android.mk b/Android.mk
index f564459..a94414d 100644
--- a/Android.mk
+++ b/Android.mk
@@ -202,6 +202,7 @@
 	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 \
diff --git a/api/current.txt b/api/current.txt
index 5493666..927b588 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -9336,6 +9336,7 @@
     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 @@
     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);
diff --git a/api/system-current.txt b/api/system-current.txt
index d6d4f5d..9ff969f 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -9630,6 +9630,7 @@
     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 @@
     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);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 054dafe..3029b11 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1295,6 +1295,14 @@
 
     /**
      * 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
      * <a href="http://www.khronos.org/registry/gles/extensions/ANDROID/ANDROID_extension_pack_es31a.txt">
      * Android Extension Pack</a>.
diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl
index 961a3f4..940565f 100644
--- a/core/java/android/nfc/INfcAdapter.aidl
+++ b/core/java/android/nfc/INfcAdapter.aidl
@@ -26,6 +26,7 @@
 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 @@
 {
     INfcTag getNfcTagInterface();
     INfcCardEmulation getNfcCardEmulationInterface();
+    INfcFCardEmulation getNfcFCardEmulationInterface();
     INfcAdapterExtras getNfcAdapterExtrasInterface(in String pkg);
 
     int getState();
diff --git a/core/java/android/nfc/INfcFCardEmulation.aidl b/core/java/android/nfc/INfcFCardEmulation.aidl
new file mode 100644
index 0000000..124bfac
--- /dev/null
+++ b/core/java/android/nfc/INfcFCardEmulation.aidl
@@ -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();
+}
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index ff6eb40..acd780d 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -294,6 +294,7 @@
     static INfcAdapter sService;
     static INfcTag sTagService;
     static INfcCardEmulation sCardEmulationService;
+    static INfcFCardEmulation sNfcFCardEmulationService;
 
     /**
      * The NfcAdapter object for each application context.
@@ -452,6 +453,13 @@
                 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) {
@@ -571,6 +579,15 @@
     }
 
     /**
+     * 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 @@
             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;
     }
 
diff --git a/core/java/android/nfc/cardemulation/HostNfcFService.java b/core/java/android/nfc/cardemulation/HostNfcFService.java
new file mode 100644
index 0000000..273ddeb
--- /dev/null
+++ b/core/java/android/nfc/cardemulation/HostNfcFService.java
@@ -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);
+}
diff --git a/core/java/android/nfc/cardemulation/NfcFCardEmulation.java b/core/java/android/nfc/cardemulation/NfcFCardEmulation.java
new file mode 100644
index 0000000..d61ac02
--- /dev/null
+++ b/core/java/android/nfc/cardemulation/NfcFCardEmulation.java
@@ -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();
+    }
+
+}
+
diff --git a/core/java/android/nfc/cardemulation/NfcFServiceInfo.aidl b/core/java/android/nfc/cardemulation/NfcFServiceInfo.aidl
new file mode 100644
index 0000000..56b98eb
--- /dev/null
+++ b/core/java/android/nfc/cardemulation/NfcFServiceInfo.aidl
@@ -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;
diff --git a/core/java/android/nfc/cardemulation/NfcFServiceInfo.java b/core/java/android/nfc/cardemulation/NfcFServiceInfo.java
new file mode 100644
index 0000000..b93eec1
--- /dev/null
+++ b/core/java/android/nfc/cardemulation/NfcFServiceInfo.java
@@ -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());
+    }
+}
+
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 2828d21..5a08169 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3315,6 +3315,32 @@
         <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>