org.thaliproject.p2p.btconnectorlib.internal.wifi.WifiServiceWatcher.java Source code

Java tutorial

Introduction

Here is the source code for org.thaliproject.p2p.btconnectorlib.internal.wifi.WifiServiceWatcher.java

Source

/* Copyright (c) 2015-2016 Microsoft Corporation. This software is licensed under the MIT License.
 * See the license file delivered with this project for further information.
 */
package org.thaliproject.p2p.btconnectorlib.internal.wifi;

import android.net.wifi.p2p.WifiP2pDevice;
import android.net.wifi.p2p.WifiP2pManager;
import android.net.wifi.p2p.WifiP2pManager.DnsSdServiceResponseListener;
import android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceRequest;
import android.os.Handler;
import android.util.Log;
import org.json.JSONException;
import org.thaliproject.p2p.btconnectorlib.PeerProperties;
import org.thaliproject.p2p.btconnectorlib.internal.AbstractBluetoothConnectivityAgent;

/**
 * Watcher for Wi-Fi P2P services (peers) matching the desired service type and which also have a
 * valid identity.
 */
class WifiServiceWatcher {
    public interface Listener {
        /**
         * Called when a new peer (with an appropriate service) is discovered.
         * @param peerProperties The discovered peer device with an appropriate service.
         */
        void onServiceDiscovered(PeerProperties peerProperties);
    }

    private static final String TAG = WifiServiceWatcher.class.getName();
    private static final long START_SERVICE_DISCOVERY_DELAY_IN_MILLISECONDS = 1000;
    private final WifiP2pManager mP2pManager;
    private final WifiP2pManager.Channel mP2pChannel;
    private final Listener mListener;
    private final String mServiceType;
    private DnsSdServiceResponseListener mDnsSdServiceResponseListener = null;
    private boolean mIsRestarting = false;

    /**
     * Constructor.
     * @param listener The listener.
     * @param p2pManager The Wi-Fi P2P manager.
     * @param p2pChannel The Wi-Fi P2P channel.
     * @param serviceType The service type.
     */
    public WifiServiceWatcher(Listener listener, WifiP2pManager p2pManager, WifiP2pManager.Channel p2pChannel,
            String serviceType) {
        mP2pManager = p2pManager;
        mP2pChannel = p2pChannel;
        mListener = listener;
        mServiceType = serviceType;

        mDnsSdServiceResponseListener = new MyDnsSdServiceResponseListener();
        mP2pManager.setDnsSdResponseListeners(mP2pChannel, mDnsSdServiceResponseListener, null);
    }

    /**
     * Starts the service discovery.
     */
    public synchronized void start() {
        mIsRestarting = false;
        WifiP2pDnsSdServiceRequest request = WifiP2pDnsSdServiceRequest.newInstance(mServiceType);
        final WifiServiceWatcher thisInstance = this;
        final Handler handler = new Handler();

        mP2pManager.addServiceRequest(mP2pChannel, request, new WifiP2pManager.ActionListener() {
            @Override
            public void onSuccess() {
                Log.i(TAG, "Service request added successfully");

                // There is supposedly a possible race-condition bug with the service discovery.
                // Thus, to avoid it, we are delaying the service discovery initialization here.
                handler.postDelayed(new Runnable() {
                    public void run() {
                        thisInstance.mP2pManager.discoverServices(thisInstance.mP2pChannel,
                                new WifiP2pManager.ActionListener() {
                                    @Override
                                    public void onSuccess() {
                                        Log.d(TAG, "Service discovery started successfully");
                                    }

                                    @Override
                                    public void onFailure(int reason) {
                                        Log.e(TAG,
                                                "Failed to start the service discovery, got error code: " + reason);

                                        // Uncomment the following to auto-restart
                                        //thisInstance.stop(true); // Restart
                                    }
                                });
                    }
                }, START_SERVICE_DISCOVERY_DELAY_IN_MILLISECONDS);
            }

            @Override
            public void onFailure(int reason) {
                Log.e(TAG, "Failed to add a service request, got error code: " + reason);

                // Uncomment the following to auto-restart
                //thisInstance.stop(true); // Restart
            }
        });
    }

    /**
     * Stops the service discovery.
     * @param restart If true, will restart.
     */
    public synchronized void stop(boolean restart) {
        mIsRestarting = restart;

        mP2pManager.clearServiceRequests(mP2pChannel, new WifiP2pManager.ActionListener() {
            @Override
            public void onSuccess() {
                if (mIsRestarting) {
                    start();
                } else {
                    Log.d(TAG, "Service requests cleared successfully");
                }
            }

            @Override
            public void onFailure(int reason) {
                Log.e(TAG, "Failed to clear service requests, got error code: " + reason);

                if (mIsRestarting) {
                    start();
                }
            }
        });
    }

    /**
     * Stops the service discovery.
     */
    public void stop() {
        stop(false);
    }

    /**
     * Restarts the service discovery.
     */
    public synchronized void restart() {
        Log.d(TAG, "restart: Restarting...");
        stop(true);
    }

    /**
     * Custom listener for services (peers).
     */
    private class MyDnsSdServiceResponseListener implements WifiP2pManager.DnsSdServiceResponseListener {
        /**
         * Handles found services. Checks if the service type matches ours and that the received
         * identity string is valid. Notifies the listener, when peers are found.
         * @param identityString The identity string.
         * @param serviceType The service type.
         * @param p2pDevice The P2P device associated with the service.
         */
        @Override
        public void onDnsSdServiceAvailable(String identityString, String serviceType, WifiP2pDevice p2pDevice) {
            Log.i(TAG, "onDnsSdServiceAvailable: Identity: \"" + identityString + "\", service type: \""
                    + serviceType + "\"");

            if (serviceType.startsWith(mServiceType)) {
                PeerProperties peerProperties = new PeerProperties();
                boolean resolvedPropertiesOk = false;

                try {
                    resolvedPropertiesOk = AbstractBluetoothConnectivityAgent
                            .getPropertiesFromIdentityString(identityString, peerProperties);
                } catch (JSONException e) {
                    Log.e(TAG, "onDnsSdServiceAvailable: Failed to resolve peer properties: " + e.getMessage(), e);
                }

                if (resolvedPropertiesOk) {
                    Log.d(TAG, "onDnsSdServiceAvailable: Resolved peer properties: " + peerProperties.toString());
                    peerProperties.setServiceType(serviceType);
                    peerProperties.setDeviceName(p2pDevice.deviceName);
                    peerProperties.setDeviceAddress(p2pDevice.deviceAddress);
                }

                mListener.onServiceDiscovered(peerProperties);
            } else {
                Log.i(TAG, "onDnsSdServiceAvailable: This not our service: " + mServiceType + " != " + serviceType);
            }
        }
    }
}