[JAVA] Android 8.0 --Wi-Fi Aware Note

Below ↓ machine translation https://developer.android.com/guide/topics/connectivity/wifi-aware.html#create_a_connection

Overview

On some devices running Android 8.0 (API level 26) and higher, Wi-Fi Aware provides the ability to discover and connect directly to each other without any other type of connectivity between them, such as Wi-Fi Access Point or Cellular. Wi-Fi Aware is also known as Neighbor Awareness Networking or NAN.

On some devices running Android 8.0 (API level 26) or later, Wi-Fi Aware, such as Wi-Fi access points and Cellular, can detect and connect directly to each other without any other type of connection. .. Wi-Fi Aware is also known as Neighbor Awareness Networking or NAN.

Wi-Fi Aware networking works by forming clusters with neighboring devices, or by creating a new cluster if the device is the first one in an area. This clustering behavior is device-wide—apps have no control over clustering behavior—and the behavior is managed by the Wi-Fi Aware system service. Apps use the Wi-Fi Aware APIs to talk to the Wi-Fi Aware system service which, in turn, manages the Wi-Fi Aware hardware on the device.

Wi-Fi enabled networks work by forming a cluster with neighboring devices, or by creating a new cluster if the device is the first in the area. The behavior of this clustering is device-wide, the application has no control over the clustering behavior, and that behavior is managed by the Wi-Fi Aware system service. The app uses the Wi-Fi Aware API to communicate with the Wi-Fi Aware system service, which manages the Wi-Fi Aware hardware on your device.

The Wi-Fi Aware APIs are available to apps that target Android 8.0 (API level 26), and let apps perform the following operations:

The Wi-Fi Aware API can be used in applications targeting Android 8.0 (API level 26), allowing the app to do the following:

Discover Other Devices-The API has a mechanism for finding other devices nearby. The process begins when one device exposes a discoverable service. Then, when the device subscribes to one or more services and enters the publisher's Wi-Fi range, the subscriber will be notified that a matching publisher has been found. After the subscriber discovers the publisher, the subscriber can send a short message or establish a network connection with the discovered device.

Creating a network connection-You can create a two-way Wi-Fi Aware network connection without an access point after the two devices have detected each other via Wi-Fi Aware discovery or other mechanisms such as Bluetooth or BLE.

Wi-Fi Aware network connections are more reliable than Wi-Fi P2P connections and support higher throughput rates across longer distances than Bluetooth connections. These types of connections are useful for apps that share data between users, such as photo-sharing apps.

Wi-Fi enabled network connections are more reliable than Wi-Fi P2P connections and support higher throughput over longer distances than Bluetooth connections. These types of connections are useful for apps that share data between users, such as photo sharing apps.

Wi-Fi Aware setup

Permission settings

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

Check your device's Wi-Fi Aware support

context.getPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI_AWARE);

Registering a broadcast receiver to receive Wi-Fi Aware availability change notifications

IntentFilter filter =
    new IntentFilter(WifiAwareManager.WIFI_AWARE_STATE_CHANGED_ACTION);
BroadcastReceiver myReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(final Context context, final Intent intent) {
        if (WifiAwareManager.isAvailable()) {
            //Wi-What to do when Fi Aware becomes available
        } else {
            //Wi-What to do when Fi Aware becomes unavailable
        }
    }
};
context.registerReceiver(myReceiver, filter);

Get session

To start using Wi-Fi Aware, your app must obtain a WifiAwareSession by calling attach(). This method does the following:

To start using Wi-Fi Aware, your application needs to call attach () to get a WifiAwareSession. This method does the following:

Publish service

To make the service discoverable, call the WiFiAwareSession # publish () method.

PublishConfig config = new PublishConfig.Builder()
    .setServiceName(AWARE_FILE_SHARE_SERVICE_NAME)
    .build();

mAwareSession.publish(config, new DiscoverySessionCallback() {
    @Override
    public void onPublishStarted(PublishDiscoverySession session) {
        //Called if the publish is successful.
        //The device running the matching subscriber app is the public device Wi-When you move to the Fi range, the subscriber discovers the service. When a subscriber discovers a publisher, the publisher does not receive notification until the subscriber sends a message to the publisher.
    }
    @Override
    public void onMessageReceived(PeerHandle peerHandle, byte[] message) {
        //The publisher receives a notification when the subscriber sends a message to the publisher. When that happens, the onMessageReceived () callback method is executed. You can use the PeerHandle argument of this method to send a message back to or create a connection to the subscriber.
    }, null);

To stop publishing the service, call DiscoverySession.close(). Discovery sessions are associated with their parent WifiAwareSession. If the parent session is closed, its associated discovery sessions are also closed. However, the system doesn't guarantee when out-of-scope sessions are closed, so we recommend that you manually call DiscoverySession.close().

To stop publishing the service, call DiscoverySession.close (). The discovery session is associated with the parent WifiAwareSession. If the parent session is closed, its associated discovery session is also closed. However, it is not guaranteed when an out-of-scope session is closed, so it is recommended that you manually call DiscoverySession.close ().

Service subscription

Call the WiFiAwareSession # subscribe () method to subscribe to the service.

SubscribeConfig config = new SubscribeConfig.Builder()
    .setServiceName(AWARE_FILE_SHARE_SERVICE_NAME)
    .build();

mAwareSession.subscribe(config, new DiscoverySessionCallback() {
    @Override
    public void onSubscribeStarted(SubscribeDiscoverySession session) {
        //If the subscribe operation is successful, the system makes an onSubscribeStarted () callback in the application. You need to save this reference because you can use the SubscribeDiscoverySession argument in the callback to communicate with the publisher after the app detects it. You can update the description at any time by calling updateSubscribe () in the discovery session.
    }

    @Override
    public void onServiceDiscovered(PeerHandle peerHandle,
            byte[] serviceSpecificInfo, List<byte[]> matchFilter) {
        //Matching publisher is Wi-When in Fi, the system executes the onServiceDiscovered () callback method. You can use the PeerHandle argument in this callback to send a message or create a connection to that publisher.
    }
}, null);

Send message

To send a message to another device, you need the following objects: A DiscoverySession. This object allows you to call sendMessage(). Your app gets a DiscoverySession by either publishing a service or subscribing to a service. The other device's PeerHandle, so you know where to send the message. Your app gets another device's PeerHandle in one of two ways: Your app publishes a service. Then, when it receives a message from a subscriber, your app gets the subscriber's PeerHandle from the onMessageReceived() callback. Your app subscribes to a service. Then, when it discovers a matching publisher, your app gets the publisher's PeerHandle from the onServiceDiscovered() callback. To send a message, call sendMessage(). The following callbacks might then occur:

To send a message to another device, you need the following objects: Discovery session. You can use this object to call sendMessage (). Your app gets a Discovery Session by publishing or subscribing to the service. PeerHandle on other devices knows where to send the message. Your app gets PeerHandle on another device in one of two ways: Your app publishes the service. Then, when it receives a message from the subscriber, the application gets the subscriber's PeerHandle from the onMessageReceived () callback. Your app is subscribed to the service. Then, when it finds a matching publisher, it gets the publisher's PeerHandle from the onServiceDiscovered () callback. To send a message, call sendMessage (). The following callbacks can occur:

When the message is successfully received by the peer, the system executes the onMessageSendSucceeded() callback in the sending app. When the peer receives a message, the system executes the onMessageReceived() callback in the receiving app. Note: Messages are generally used for lightweight messaging, as they might not be delivered and are limited to about 255 bytes in length. To determine the exact length limit, call getMaxServiceSpecificInfoLength(). For high speed, bi-directional communication, your app should create a connection instead.

If the message is successfully received by the peer, the system will make an onMessageSendSucceeded () callback in the sending app. When the peer receives the message, the receiving application makes an onMessageReceived () callback. Note: Messages are commonly used for lightweight messaging. This is because the message may not be delivered and is limited to approximately 255 bytes in length. To determine the exact length limit, call getMaxServiceSpecificInfoLength (). For high-speed two-way communication, the app should create a connection instead.

Connect

There are two ways to create a Wi-Fi Aware connection. The first way assumes that you have used Wi-Fi Aware to discover the other device and you have the other device's PeerHandle. The second way assumes that you have discovered the other device's MAC address through some other mechanism, such as Bluetooth or BLE. This is known as out-of-band discovery, or OOB.

There are two ways to create a Wi-Fi Aware connection. The first method assumes that you are using Wi-Fi Aware to detect other devices and are using the PeerHandle of the other device. The second method assumes that you have detected the MAC address of another device using other mechanisms such as Bluetooth or BLE. This is called out-of-band detection, or OOB.

Regardless of which method you choose, there are always two devices in a Wi-Fi Aware connection: an initiator and a responder. If you're using Wi-Fi Aware discovery, then the roles are fixed and don't need to be explicitly specified: the subscriber is the initiator and the publisher is the responder. If you are using out-of-band discovery, then the devices need to negotiate these roles on their own.

Regardless of which method you choose, there are always two devices in your Wi-Fi Aware connection: the initiator and the responder. If you are using Wi-Fi Aware detection, the role is fixed and does not need to be explicitly specified. The subscriber is the initiator and the publisher is the responder. If you are using out-of-band detection, your device will have to negotiate these roles on its own.

To create a connection, complete the following sequence of steps:

  1. Create a network specifier: For Wi-Fi Aware discovery, call either DiscoverySession.createNetworkSpecifierOpen() or DiscoverySession.createNetworkSpecifierPassphrase() from the publisher and subscriber. For OOB discovery, call either WifiAwareSession.createNetworkSpecifierOpen() or WifiAwareSession.createNetworkSpecifierPassphrase() from both devices. The responder isn't required to provide a MAC address or a PeerHandle. If no MAC address or PeerHandle is specified, the device accepts all connection requests.

To create a connection, do the following:

  1. Create a network specifier: For Wi-Fi Aware discovery, call DiscoverySession.createNetworkSpecifierOpen () or DiscoverySession.createNetworkSpecifierPassphrase () from publishers and subscribers. For OOB discovery, call WifiAwareSession.createNetworkSpecifierOpen () or WifiAwareSession.createNetworkSpecifierPassphrase () from both devices. The responder does not need to provide a MAC address or PeerHandle. If no MAC address or PeerHandle is specified, the device accepts all connection requests.
  1. Build a network request, setting the transport mechanism to TRANSPORT_WIFI_AWARE:

Set the transport mechanism to TRANSPORT_WIFI_AWARE to make a network request.

NetworkRequest myNetworkRequest = new NetworkRequest.Builder()
     .addTransportType(NetworkCapabilities.TRANSPORT_WIFI_AWARE)
     .setNetworkSpecifier(networkSpecifier)
     .build();
  1. Call requestNetwork() and provide the following callback methods:

Call requestNetwork () and provide the following callback method:

mCallback = new ConnectivityManager.NetworkCallback() {
    @Override
    public void onAvailable(Network network) {
        ...
    }
    @Override
    public void onLinkPropertiesChanged(Network network,
            LinkProperties linkProperties) {
        ...
    }
    @Override
    public void onLost(Network network) {
        ...
    }
};
mConnMgr.requestNetwork(networkRequest, mCallback);

The appropriate callback methods are executed when the network connection is available, changed, or lost.

Appropriate callback methods are executed when a network connection is available, modified, or lost.

4 When you're finished with the network connection, call unregisterNetworkCallback(). Note: Building a network request and specifying the required network capabilities aren't specific to the Wi-Fi Aware API. For more information on working with network requests, see ConnectivityManager.

Call unregisterNetworkCallback () when the network connection is closed. Note: Creating network requests and specifying required network features is not specific to the Wi-Fi Aware API. For more information on handling network requests, see Connectivity Manager.


Creating a test app based on the above

Publisher side that starts publishing and receives messages from subscribers referring to the above Try the app and the subscriber-side app implementation that subscribes and sends messages to the publisher.

Publisher activity

package com.example.user.wifiawaretest;

import android.app.Activity;
import android.content.pm.PackageManager;
import android.net.wifi.aware.AttachCallback;
import android.net.wifi.aware.DiscoverySessionCallback;
import android.net.wifi.aware.PeerHandle;
import android.net.wifi.aware.PublishConfig;
import android.net.wifi.aware.PublishDiscoverySession;
import android.net.wifi.aware.WifiAwareManager;
import android.net.wifi.aware.WifiAwareSession;
import android.os.Handler;
import android.os.Bundle;
import android.widget.Toast;

public class MainActivity extends Activity {

    private WifiAwareSession mAwareSession;
    private Handler mHandler = new Handler();
    public static final String AWARE_SERVICE_NAME = "Aware Service";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_AWARE)) {
            Toast.makeText(this, "Wi-Fi Aware not supoortted", Toast.LENGTH_SHORT).show();
            return;
        }

        WifiAwareManager was = (WifiAwareManager)getSystemService(WifiAwareManager.class);

        was.attach(new MyAttachCallback(), mHandler);
    }

    class MyAttachCallback extends AttachCallback {
        @Override
        public void onAttachFailed() {
            Toast.makeText(MainActivity.this, "onAttachFailed", Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onAttached(WifiAwareSession session) {
            Toast.makeText(MainActivity.this, "onAttach", Toast.LENGTH_SHORT).show();

            MainActivity.this.mAwareSession = session;
            PublishConfig config = new PublishConfig.Builder()
                    .setServiceName(AWARE_SERVICE_NAME)
                    .build();
            MainActivity.this.mAwareSession.publish(config, new DiscoverySessionCallback() {
                @Override
                public void onPublishStarted(PublishDiscoverySession session) {
                    Toast.makeText(MainActivity.this, "onPublishStarted", Toast.LENGTH_SHORT).show();
                }

                @Override
                public void onMessageReceived(PeerHandle peerHandle, byte[] message) {
                    Toast.makeText(MainActivity.this, "onMessageReceived : " + message.toString(), Toast.LENGTH_SHORT).show();
                }
            }, null);
        }
    }
}

Subscriber side

package com.example.user.wifiawaresubscribertest;

import android.app.Activity;
import android.content.pm.PackageManager;
import android.net.wifi.aware.AttachCallback;
import android.net.wifi.aware.DiscoverySessionCallback;
import android.net.wifi.aware.PeerHandle;
import android.net.wifi.aware.PublishConfig;
import android.net.wifi.aware.PublishDiscoverySession;
import android.net.wifi.aware.SubscribeConfig;
import android.net.wifi.aware.SubscribeDiscoverySession;
import android.net.wifi.aware.WifiAwareManager;
import android.net.wifi.aware.WifiAwareSession;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Toast;

import java.util.List;

public class MainActivity extends Activity {

    private WifiAwareSession mAwareSession;
    private Handler mHandler = new Handler();
    public static final String AWARE_SERVICE_NAME = "Aware Service";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_AWARE)) {
            Toast.makeText(this, "Wi-Fi Aware not supoortted", Toast.LENGTH_SHORT).show();
            return;
        }

        WifiAwareManager was = (WifiAwareManager)getSystemService(WifiAwareManager.class);

        was.attach(new MyAttachCallback(), mHandler);
    }

    class MyAttachCallback extends AttachCallback {
        @Override
        public void onAttachFailed() {
            Toast.makeText(MainActivity.this, "onAttachFailed", Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onAttached(WifiAwareSession session) {
            Toast.makeText(MainActivity.this, "onAttach", Toast.LENGTH_SHORT).show();

            MainActivity.this.mAwareSession = session;

            SubscribeConfig config = new SubscribeConfig.Builder()
                    .setServiceName(AWARE_SERVICE_NAME)
                    .build();

            mAwareSession.subscribe(config, new DiscoverySessionCallback() {

                private PeerHandle mPeerHandle = null;
                @Override
                public void onSubscribeStarted(SubscribeDiscoverySession session) {
                    if (mPeerHandle != null) {
                        int messageId = 1;
                        session.sendMessage(mPeerHandle, messageId, "Test Message".getBytes());
                    }
                }

                @Override
                public void onServiceDiscovered(PeerHandle peerHandle,
                                                byte[] serviceSpecificInfo, List<byte[]> matchFilter) {
                    mPeerHandle = peerHandle;
                }
            }, null);

        }
    }
}

Common (permission setting)

AndroidManifest.xml


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.user.wifiawaretest">
    
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

Recommended Posts

Android 8.0 --Wi-Fi Aware Note
Note