Merge "interface for nfc handover supplicant commands"
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 53f46eb..ca897d5 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -156,16 +156,12 @@
         android:name="android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED" />
     <protected-broadcast android:name="android.bluetooth.pbap.intent.action.PBAP_STATE_CHANGED" />
     <protected-broadcast android:name="android.btopp.intent.action.INCOMING_FILE_NOTIFICATION" />
-    <protected-broadcast android:name="android.btopp.intent.action.BT_OPP_HANDOVER_STARTED" />
-    <protected-broadcast android:name="android.btopp.intent.action.TRANSFER_COMPLETE" />
     <protected-broadcast android:name="android.btopp.intent.action.USER_CONFIRMATION_TIMEOUT" />
-    <protected-broadcast android:name="android.btopp.intent.action.BT_OPP_TRANSFER_PROGRESS" />
     <protected-broadcast android:name="android.btopp.intent.action.LIST" />
     <protected-broadcast android:name="android.btopp.intent.action.OPEN_OUTBOUND" />
     <protected-broadcast android:name="android.btopp.intent.action.HIDE_COMPLETE" />
     <protected-broadcast android:name="android.btopp.intent.action.CONFIRM" />
     <protected-broadcast android:name="android.btopp.intent.action.HIDE" />
-    <protected-broadcast android:name="android.btopp.intent.action.BT_OPP_TRANSFER_DONE" />
     <protected-broadcast android:name="android.btopp.intent.action.RETRY" />
     <protected-broadcast android:name="android.btopp.intent.action.OPEN" />
     <protected-broadcast android:name="android.btopp.intent.action.OPEN_INBOUND" />
@@ -284,7 +280,13 @@
     <protected-broadcast
         android:name="android.intent.action.PERMISSION_RESPONSE_RECEIVED" />
     <!-- Defined in RestrictionsManager -->
+
     <protected-broadcast android:name="android.intent.action.REQUEST_PERMISSION" />
+    <protected-broadcast android:name="android.nfc.handover.intent.action.HANDOVER_STARTED" />
+    <protected-broadcast android:name="android.nfc.handover.intent.action.TRANSFER_DONE" />
+    <protected-broadcast android:name="android.nfc.handover.intent.action.TRANSFER_PROGRESS" />
+    <protected-broadcast android:name="android.nfc.handover.intent.action.TRANSFER_DONE" />
+
 
     <!-- ====================================== -->
     <!-- Permissions for things that cost money -->
@@ -877,6 +879,14 @@
 	android:permissionGroup="android.permission-group.NETWORK"
 	android:protectionLevel="signature|system" />
 
+    <!-- Allows sending and receiving handover transfer status from Wifi and Bluetooth
+         @hide
+    -->
+    <permission android:name="android.permission.NFC_HANDOVER_STATUS"
+                android:label="@string/permlab_handoverStatus"
+                android:description="@string/permdesc_handoverStatus"
+                android:protectionLevel="signature|system" />
+
     <!-- ================================== -->
     <!-- Permissions for accessing accounts -->
     <!-- ================================== -->
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 3da6669..7d474a4 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2137,6 +2137,9 @@
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_accessDrmCertificates">Allows an application to provision and use DRM certficates. Should never be needed for normal apps.</string>
 
+    <string name="permlab_handoverStatus">Receive handover transfer broadcasts.</string>
+    <string name="permdesc_handoverStatus">Allows receiving handover transfer status information.</string>
+
     <!-- Policy administration -->
 
     <!-- Title of policy access to limiting the user's password choices -->
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 3bff2ad..1b92e3f 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -13959,6 +13959,8 @@
 
         // Make sure that the user who is receiving this broadcast is started.
         // If not, we will just skip it.
+
+
         if (userId != UserHandle.USER_ALL && mStartedUsers.get(userId) == null) {
             if (callingUid != Process.SYSTEM_UID || (intent.getFlags()
                     & Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0) {
@@ -13974,8 +13976,8 @@
          */
         int callingAppId = UserHandle.getAppId(callingUid);
         if (callingAppId == Process.SYSTEM_UID || callingAppId == Process.PHONE_UID
-                || callingAppId == Process.SHELL_UID || callingAppId == Process.BLUETOOTH_UID
-                || callingUid == 0) {
+            || callingAppId == Process.SHELL_UID || callingAppId == Process.BLUETOOTH_UID
+            || callingAppId == Process.NFC_UID || callingUid == 0) {
             // Always okay.
         } else if (callerApp == null || !callerApp.persistent) {
             try {
diff --git a/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl b/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl
index 1c9c40d..ee2e895 100644
--- a/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl
+++ b/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl
@@ -26,6 +26,7 @@
 interface IWifiP2pManager
 {
     Messenger getMessenger();
+    Messenger getP2pStateMachineMessenger();
     void setMiracastMode(int mode);
 }
 
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
index 3ed2406..6409450 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
@@ -276,6 +276,13 @@
     public static final String WIFI_P2P_PERSISTENT_GROUPS_CHANGED_ACTION =
         "android.net.wifi.p2p.PERSISTENT_GROUPS_CHANGED";
 
+    /**
+     * The lookup key for a handover message returned by the WifiP2pService.
+     * @hide
+     */
+    public static final String EXTRA_HANDOVER_MESSAGE =
+            "android.net.wifi.p2p.EXTRA_HANDOVER_MESSAGE";
+
     IWifiP2pManager mService;
 
     private static final int BASE = Protocol.BASE_WIFI_P2P_MANAGER;
@@ -446,6 +453,21 @@
     /** @hide */
     public static final int SET_CHANNEL_SUCCEEDED                   = BASE + 73;
 
+    /** @hide */
+    public static final int GET_HANDOVER_REQUEST                    = BASE + 75;
+    /** @hide */
+    public static final int GET_HANDOVER_SELECT                     = BASE + 76;
+    /** @hide */
+    public static final int RESPONSE_GET_HANDOVER_MESSAGE           = BASE + 77;
+    /** @hide */
+    public static final int INITIATOR_REPORT_NFC_HANDOVER           = BASE + 78;
+    /** @hide */
+    public static final int RESPONDER_REPORT_NFC_HANDOVER           = BASE + 79;
+    /** @hide */
+    public static final int REPORT_NFC_HANDOVER_SUCCEEDED           = BASE + 80;
+    /** @hide */
+    public static final int REPORT_NFC_HANDOVER_FAILED              = BASE + 81;
+
 
     /**
      * Create a new WifiP2pManager instance. Applications use
@@ -627,6 +649,14 @@
     }
 
     /**
+     * Interface for callback invocation when Handover Request or Select Message is available
+     * @hide
+     */
+    public interface HandoverMessageListener {
+        public void onHandoverMessageAvailable(String handoverMessage);
+    }
+
+    /**
      * A channel that connects the application to the Wifi p2p framework.
      * Most p2p operations require a Channel as an argument. An instance of Channel is obtained
      * by doing a call on {@link #initialize}
@@ -687,6 +717,7 @@
                     case START_LISTEN_FAILED:
                     case STOP_LISTEN_FAILED:
                     case SET_CHANNEL_FAILED:
+                    case REPORT_NFC_HANDOVER_FAILED:
                         if (listener != null) {
                             ((ActionListener) listener).onFailure(message.arg1);
                         }
@@ -712,6 +743,7 @@
                     case START_LISTEN_SUCCEEDED:
                     case STOP_LISTEN_SUCCEEDED:
                     case SET_CHANNEL_SUCCEEDED:
+                    case REPORT_NFC_HANDOVER_SUCCEEDED:
                         if (listener != null) {
                             ((ActionListener) listener).onSuccess();
                         }
@@ -745,7 +777,17 @@
                                 onPersistentGroupInfoAvailable(groups);
                         }
                         break;
-                   default:
+                    case RESPONSE_GET_HANDOVER_MESSAGE:
+                        Bundle handoverBundle = (Bundle) message.obj;
+                        if (listener != null) {
+                            String handoverMessage = handoverBundle != null
+                                    ? handoverBundle.getString(EXTRA_HANDOVER_MESSAGE)
+                                    : null;
+                            ((HandoverMessageListener) listener)
+                                    .onHandoverMessageAvailable(handoverMessage);
+                        }
+                        break;
+                    default:
                         Log.d(TAG, "Ignored " + message);
                         break;
                 }
@@ -841,7 +883,20 @@
      * @return Channel instance that is necessary for performing any further p2p operations
      */
     public Channel initialize(Context srcContext, Looper srcLooper, ChannelListener listener) {
-        Messenger messenger = getMessenger();
+        return initalizeChannel(srcContext, srcLooper, listener, getMessenger());
+    }
+
+    /**
+     * Registers the application with the Wi-Fi framework. Enables system-only functionality.
+     * @hide
+     */
+    public Channel initializeInternal(Context srcContext, Looper srcLooper,
+                                      ChannelListener listener) {
+        return initalizeChannel(srcContext, srcLooper, listener, getP2pStateMachineMessenger());
+    }
+
+    private Channel initalizeChannel(Context srcContext, Looper srcLooper, ChannelListener listener,
+                                     Messenger messenger) {
         if (messenger == null) return null;
 
         Channel c = new Channel(srcContext, srcLooper, listener);
@@ -1327,4 +1382,62 @@
         }
     }
 
+    /**
+     * Get a reference to P2pStateMachine handler. This is used to establish
+     * a priveleged AsyncChannel communication with WifiP2pService.
+     *
+     * @return Messenger pointing to the WifiP2pService handler
+     * @hide
+     */
+    public Messenger getP2pStateMachineMessenger() {
+        try {
+            return mService.getP2pStateMachineMessenger();
+        } catch (RemoteException e) {
+            return null;
+        }
+    }
+
+    /**
+     * Get a handover request message for use in WFA NFC Handover transfer.
+     * @hide
+     */
+    public void getNfcHandoverRequest(Channel c, HandoverMessageListener listener) {
+        checkChannel(c);
+        c.mAsyncChannel.sendMessage(GET_HANDOVER_REQUEST, 0, c.putListener(listener));
+    }
+
+
+    /**
+     * Get a handover select message for use in WFA NFC Handover transfer.
+     * @hide
+     */
+    public void getNfcHandoverSelect(Channel c, HandoverMessageListener listener) {
+        checkChannel(c);
+        c.mAsyncChannel.sendMessage(GET_HANDOVER_SELECT, 0, c.putListener(listener));
+    }
+
+    /**
+     * @hide
+     */
+    public void initiatorReportNfcHandover(Channel c, String handoverSelect,
+                                              ActionListener listener) {
+        checkChannel(c);
+        Bundle bundle = new Bundle();
+        bundle.putString(EXTRA_HANDOVER_MESSAGE, handoverSelect);
+        c.mAsyncChannel.sendMessage(INITIATOR_REPORT_NFC_HANDOVER, 0,
+                c.putListener(listener), bundle);
+    }
+
+
+    /**
+     * @hide
+     */
+    public void responderReportNfcHandover(Channel c, String handoverRequest,
+                                              ActionListener listener) {
+        checkChannel(c);
+        Bundle bundle = new Bundle();
+        bundle.putString(EXTRA_HANDOVER_MESSAGE, handoverRequest);
+        c.mAsyncChannel.sendMessage(RESPONDER_REPORT_NFC_HANDOVER, 0,
+                c.putListener(listener), bundle);
+    }
 }