[DPP] Added new DPP Initiator APIs and callbacks

Added new DPP Initiator APIs and callbacks:
startDppAsConfiguratorInitiator
startDppAsEnrolleeInitiator
stopDppSession
The Initiator APIs are asynchronous and provide events and status codes
through callbacks.

Bug: 112197021
Test: atest DppManagerTest
Change-Id: Ib2226a5e6d94b1d6247f958513c858cf38686ce8
diff --git a/Android.bp b/Android.bp
index 4e7a7b4..51bbd7c 100644
--- a/Android.bp
+++ b/Android.bp
@@ -631,6 +631,7 @@
         "wifi/java/android/net/wifi/rtt/IRttCallback.aidl",
         "wifi/java/android/net/wifi/rtt/IWifiRttManager.aidl",
         "wifi/java/android/net/wifi/hotspot2/IProvisioningCallback.aidl",
+        "wifi/java/android/net/wifi/IDppCallback.aidl",
         "wifi/java/android/net/wifi/IWifiScanner.aidl",
         "packages/services/PacProcessor/com/android/net/IProxyService.aidl",
         "packages/services/Proxy/com/android/net/IProxyCallback.aidl",
diff --git a/api/system-current.txt b/api/system-current.txt
index d981399..a6a6829 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -3629,6 +3629,26 @@
 
 package android.net.wifi {
 
+  public abstract class DppStatusCallback {
+    ctor public DppStatusCallback();
+    method public abstract void onConfiguratorSuccess(int);
+    method public abstract void onEnrolleeSuccess(int);
+    method public abstract void onFailure(int);
+    method public abstract void onProgress(int);
+    field public static final int DPP_EVENT_FAILURE = -7; // 0xfffffff9
+    field public static final int DPP_EVENT_FAILURE_AUTHENTICATION = -2; // 0xfffffffe
+    field public static final int DPP_EVENT_FAILURE_BUSY = -5; // 0xfffffffb
+    field public static final int DPP_EVENT_FAILURE_CONFIGURATION = -4; // 0xfffffffc
+    field public static final int DPP_EVENT_FAILURE_INVALID_NETWORK = -9; // 0xfffffff7
+    field public static final int DPP_EVENT_FAILURE_INVALID_URI = -1; // 0xffffffff
+    field public static final int DPP_EVENT_FAILURE_NOT_COMPATIBLE = -3; // 0xfffffffd
+    field public static final int DPP_EVENT_FAILURE_NOT_SUPPORTED = -8; // 0xfffffff8
+    field public static final int DPP_EVENT_FAILURE_TIMEOUT = -6; // 0xfffffffa
+    field public static final int DPP_EVENT_PROGRESS_AUTHENTICATION_SUCCESS = 0; // 0x0
+    field public static final int DPP_EVENT_PROGRESS_RESPONSE_PENDING = 1; // 0x1
+    field public static final int DPP_EVENT_SUCCESS_CONFIGURATION_SENT = 0; // 0x0
+  }
+
   public deprecated class RttManager {
     method public void disableResponder(android.net.wifi.RttManager.ResponderCallback);
     method public void enableResponder(android.net.wifi.RttManager.ResponderCallback);
@@ -3858,7 +3878,10 @@
     method public void save(android.net.wifi.WifiConfiguration, android.net.wifi.WifiManager.ActionListener);
     method public void setDeviceMobilityState(int);
     method public boolean setWifiApConfiguration(android.net.wifi.WifiConfiguration);
+    method public void startDppAsConfiguratorInitiator(java.lang.String, int, int, android.os.Handler, android.net.wifi.DppStatusCallback);
+    method public void startDppAsEnrolleeInitiator(java.lang.String, android.os.Handler, android.net.wifi.DppStatusCallback);
     method public boolean startScan(android.os.WorkSource);
+    method public void stopDppSession();
     method public void unregisterNetworkRequestMatchCallback(android.net.wifi.WifiManager.NetworkRequestMatchCallback);
     field public static final int CHANGE_REASON_ADDED = 0; // 0x0
     field public static final int CHANGE_REASON_CONFIG_CHANGE = 2; // 0x2
@@ -3868,6 +3891,8 @@
     field public static final int DEVICE_MOBILITY_STATE_LOW_MVMT = 2; // 0x2
     field public static final int DEVICE_MOBILITY_STATE_STATIONARY = 3; // 0x3
     field public static final int DEVICE_MOBILITY_STATE_UNKNOWN = 0; // 0x0
+    field public static final int DPP_NETWORK_ROLE_AP = 1; // 0x1
+    field public static final int DPP_NETWORK_ROLE_STA = 0; // 0x0
     field public static final java.lang.String EXTRA_CHANGE_REASON = "changeReason";
     field public static final java.lang.String EXTRA_MULTIPLE_NETWORKS_CHANGED = "multipleChanges";
     field public static final java.lang.String EXTRA_PREVIOUS_WIFI_AP_STATE = "previous_wifi_state";
diff --git a/wifi/java/android/net/wifi/DppStatusCallback.java b/wifi/java/android/net/wifi/DppStatusCallback.java
new file mode 100644
index 0000000..fa2ab30e
--- /dev/null
+++ b/wifi/java/android/net/wifi/DppStatusCallback.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2018 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.net.wifi;
+
+import android.annotation.IntDef;
+import android.annotation.SystemApi;
+import android.os.Handler;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * DPP Status Callback. Use this callback to get status updates (success, failure, progress)
+ * from the DPP operation started with {@link WifiManager#startDppAsConfiguratorInitiator(String,
+ * int, int, Handler, DppStatusCallback)} or {@link WifiManager#startDppAsEnrolleeInitiator(String,
+ * Handler, DppStatusCallback)}
+ * @hide
+ */
+@SystemApi
+public abstract class DppStatusCallback {
+    /**
+     * DPP Success event: Configuration sent (Configurator mode).
+     */
+    public static final int DPP_EVENT_SUCCESS_CONFIGURATION_SENT = 0;
+
+    /** @hide */
+    @IntDef(prefix = { "DPP_EVENT_SUCCESS_" }, value = {
+            DPP_EVENT_SUCCESS_CONFIGURATION_SENT,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface DppSuccessStatusCode {}
+
+    /**
+     * DPP Progress event: Initial authentication with peer succeeded.
+     */
+    public static final int DPP_EVENT_PROGRESS_AUTHENTICATION_SUCCESS = 0;
+
+    /**
+     * DPP Progress event: Peer requires more time to process bootstrapping.
+     */
+    public static final int DPP_EVENT_PROGRESS_RESPONSE_PENDING = 1;
+
+    /** @hide */
+    @IntDef(prefix = { "DPP_EVENT_PROGRESS_" }, value = {
+            DPP_EVENT_PROGRESS_AUTHENTICATION_SUCCESS,
+            DPP_EVENT_PROGRESS_RESPONSE_PENDING,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface DppProgressStatusCode {}
+
+    /**
+     * DPP Failure event: Scanned QR code is either not a DPP URI, or the DPP URI has errors.
+     */
+    public static final int DPP_EVENT_FAILURE_INVALID_URI = -1;
+
+    /**
+     * DPP Failure event: Bootstrapping/Authentication initialization process failure.
+     */
+    public static final int DPP_EVENT_FAILURE_AUTHENTICATION = -2;
+
+    /**
+     * DPP Failure event: Both devices are implementing the same role and are incompatible.
+     */
+    public static final int DPP_EVENT_FAILURE_NOT_COMPATIBLE = -3;
+
+    /**
+     * DPP Failure event: Configuration process has failed due to malformed message.
+     */
+    public static final int DPP_EVENT_FAILURE_CONFIGURATION = -4;
+
+    /**
+     * DPP Failure event: DPP request while in another DPP exchange.
+     */
+    public static final int DPP_EVENT_FAILURE_BUSY = -5;
+
+    /**
+     * DPP Failure event: No response from the peer.
+     */
+    public static final int DPP_EVENT_FAILURE_TIMEOUT = -6;
+
+    /**
+     * DPP Failure event: General protocol failure.
+     */
+    public static final int DPP_EVENT_FAILURE = -7;
+
+    /**
+     * DPP Failure event: Feature or option is not supported.
+     */
+    public static final int DPP_EVENT_FAILURE_NOT_SUPPORTED = -8;
+
+    /**
+     * DPP Failure event: Invalid network provided to DPP configurator.
+     * Network must either be WPA3-Personal (SAE) or WPA2-Personal (PSK).
+     */
+    public static final int DPP_EVENT_FAILURE_INVALID_NETWORK = -9;
+
+
+    /** @hide */
+    @IntDef(prefix = {"DPP_EVENT_FAILURE_"}, value = {
+            DPP_EVENT_FAILURE_INVALID_URI,
+            DPP_EVENT_FAILURE_AUTHENTICATION,
+            DPP_EVENT_FAILURE_NOT_COMPATIBLE,
+            DPP_EVENT_FAILURE_CONFIGURATION,
+            DPP_EVENT_FAILURE_BUSY,
+            DPP_EVENT_FAILURE_TIMEOUT,
+            DPP_EVENT_FAILURE,
+            DPP_EVENT_FAILURE_NOT_SUPPORTED,
+            DPP_EVENT_FAILURE_INVALID_NETWORK,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface DppFailureStatusCode {
+    }
+
+    /**
+     * Called when local DPP Enrollee successfully receives a new Wi-Fi configuration from the
+     * peer DPP configurator. This callback marks the successful end of the DPP current DPP
+     * session, and no further callbacks will be called. This callback is the successful outcome
+     * of a DPP flow starting with {@link WifiManager#startDppAsEnrolleeInitiator(String, Handler,
+     * DppStatusCallback)}.
+     *
+     * @param newNetworkId New Wi-Fi configuration with a network ID received from the configurator
+     */
+    public abstract void onEnrolleeSuccess(int newNetworkId);
+
+    /**
+     * Called when a DPP success event takes place, except for when configuration is received from
+     * an external Configurator. The callback onSuccessConfigReceived will be used in this case.
+     * This callback marks the successful end of the current DPP session, and no further
+     * callbacks will be called. This callback is the successful outcome of a DPP flow starting with
+     * {@link WifiManager#startDppAsConfiguratorInitiator(String, int, int, Handler,
+     * DppStatusCallback)}.
+     *
+     * @param code DPP success status code.
+     */
+    public abstract void onConfiguratorSuccess(@DppSuccessStatusCode int code);
+
+    /**
+     * Called when a DPP Failure event takes place. This callback marks the unsuccessful end of the
+     * current DPP session, and no further callbacks will be called.
+     *
+     * @param code DPP failure status code.
+     */
+    public abstract void onFailure(@DppFailureStatusCode int code);
+
+    /**
+     * Called when DPP events that indicate progress take place. Can be used by UI elements
+     * to show progress.
+     *
+     * @param code DPP progress status code.
+     */
+    public abstract void onProgress(@DppProgressStatusCode int code);
+}
diff --git a/wifi/java/android/net/wifi/IDppCallback.aidl b/wifi/java/android/net/wifi/IDppCallback.aidl
new file mode 100644
index 0000000..c452c76
--- /dev/null
+++ b/wifi/java/android/net/wifi/IDppCallback.aidl
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2018 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.net.wifi;
+
+/**
+ * Interface for DPP callback.
+ *
+ * @hide
+ */
+oneway interface IDppCallback
+{
+    /**
+     * Called when local DPP Enrollee successfully receives a new Wi-Fi configuratrion from the
+     * peer DPP configurator.
+     */
+    void onSuccessConfigReceived(int newNetworkId);
+
+    /**
+     * Called when DPP success events take place, except for when configuration is received from
+     * an external Configurator. The callback onSuccessConfigReceived will be used in this case.
+     */
+    void onSuccess(int status);
+
+    /**
+     * Called when DPP Failure events take place.
+     */
+    void onFailure(int status);
+
+    /**
+     * Called when DPP events that indicate progress take place. Can be used by UI elements
+     * to show progress.
+     */
+    void onProgress(int status);
+}
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 0362a1b..1700006 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -25,6 +25,7 @@
 
 import android.net.DhcpInfo;
 import android.net.Network;
+import android.net.wifi.IDppCallback;
 import android.net.wifi.INetworkRequestMatchCallback;
 import android.net.wifi.ISoftApCallback;
 import android.net.wifi.ITrafficStateCallback;
@@ -199,5 +200,13 @@
     String[] getFactoryMacAddresses();
 
     void setDeviceMobilityState(int state);
+
+    void startDppAsConfiguratorInitiator(in IBinder binder, in String enrolleeUri,
+        int selectedNetworkId, int netRole, in IDppCallback callback);
+
+    void startDppAsEnrolleeInitiator(in IBinder binder, in String configuratorUri,
+        in IDppCallback callback);
+
+    void stopDppSession();
 }
 
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index a7c2ff0..3bd80c6 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -4541,4 +4541,146 @@
             throw e.rethrowFromSystemServer();
         }
     }
+
+    /* DPP - Device Provisioning Protocol AKA "Easy Connect" */
+
+    /**
+     * DPP Network role: Station.
+     * @hide
+     */
+    @SystemApi
+    public static final int DPP_NETWORK_ROLE_STA = 0;
+
+    /**
+     * DPP Network role: Access Point.
+     * @hide
+     */
+    @SystemApi
+    public static final int DPP_NETWORK_ROLE_AP = 1;
+
+    /** @hide */
+    @IntDef(prefix = {"DPP_NETWORK_ROLE_"}, value = {
+            DPP_NETWORK_ROLE_STA,
+            DPP_NETWORK_ROLE_AP,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface DppNetworkRole {}
+
+    /**
+     * Start DPP in Configurator-Initiator role. The current device will initiate DPP bootstrapping
+     * with a peer, and configure the peer with the SSID and password of the specified network using
+     * the DPP protocol on an encrypted link.
+     *
+     * @param enrolleeUri URI of the Enrollee obtained separately (e.g. QR code scanning)
+     * @param selectedNetworkId Selected network ID to be sent to the peer
+     * @param enrolleeNetworkRole The network role of the enrollee
+     * @param callback Callback for status updates
+     * @param handler The handler on whose thread to execute the callbacks. Null for main thread.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.NETWORK_SETTINGS,
+            android.Manifest.permission.NETWORK_SETUP_WIZARD})
+    public void startDppAsConfiguratorInitiator(@NonNull String enrolleeUri,
+            int selectedNetworkId, @DppNetworkRole int enrolleeNetworkRole,
+            @Nullable Handler handler, @NonNull DppStatusCallback callback) {
+        Looper looper = (handler == null) ? Looper.getMainLooper() : handler.getLooper();
+        Binder binder = new Binder();
+        try {
+            mService.startDppAsConfiguratorInitiator(binder, enrolleeUri, selectedNetworkId,
+                    enrolleeNetworkRole, new DppCallbackProxy(looper, callback));
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Start DPP in Enrollee-Initiator role. The current device will initiate DPP bootstrapping
+     * with a peer, and receive the SSID and password from the peer configurator.
+     *
+     * @param configuratorUri URI of the Configurator obtained separately (e.g. QR code scanning)
+     * @param callback Callback for status updates
+     * @param handler The handler on whose thread to execute the callbacks. Null for main thread.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.NETWORK_SETTINGS,
+            android.Manifest.permission.NETWORK_SETUP_WIZARD})
+    public void startDppAsEnrolleeInitiator(@NonNull String configuratorUri,
+            @Nullable Handler handler, @NonNull DppStatusCallback callback) {
+        Looper looper = (handler == null) ? Looper.getMainLooper() : handler.getLooper();
+        Binder binder = new Binder();
+        try {
+            mService.startDppAsEnrolleeInitiator(binder, configuratorUri,
+                     new DppCallbackProxy(looper, callback));
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Stop or abort a current DPP session.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.NETWORK_SETTINGS,
+            android.Manifest.permission.NETWORK_SETUP_WIZARD})
+    public void stopDppSession() {
+        try {
+            /* Request lower layers to stop/abort and clear resources */
+            mService.stopDppSession();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Helper class to support DPP callbacks
+     * @hide
+     */
+    @SystemApi
+    private static class DppCallbackProxy extends IDppCallback.Stub {
+        private final Handler mHandler;
+        private final DppStatusCallback mDppStatusCallback;
+
+        DppCallbackProxy(Looper looper, DppStatusCallback dppStatusCallback) {
+            mHandler = new Handler(looper);
+            mDppStatusCallback = dppStatusCallback;
+        }
+
+        @Override
+        public void onSuccessConfigReceived(int newNetworkId) {
+            Log.d(TAG, "DPP onSuccessConfigReceived callback");
+            mHandler.post(() -> {
+                mDppStatusCallback.onEnrolleeSuccess(newNetworkId);
+            });
+        }
+
+        @Override
+        public void onSuccess(int status) {
+            Log.d(TAG, "DPP onSuccess callback");
+            mHandler.post(() -> {
+                mDppStatusCallback.onConfiguratorSuccess(status);
+            });
+        }
+
+        @Override
+        public void onFailure(int status) {
+            Log.d(TAG, "DPP onFailure callback");
+            mHandler.post(() -> {
+                mDppStatusCallback.onFailure(status);
+            });
+        }
+
+        @Override
+        public void onProgress(int status) {
+            Log.d(TAG, "DPP onProgress callback");
+            mHandler.post(() -> {
+                mDppStatusCallback.onProgress(status);
+            });
+        }
+    }
 }