• After 15+ years, we've made a big change: Android Forums is now Early Bird Club. Learn more here.

WiFi Aware Development Help (Not Working)

I am in the process of creating an application that will be able to utilize WiFi Aware to communicate directly between devices (essentially the better alternative to Bluetooth). I am wondering if anyone has experience using this API as I am unable to properly implement the attach() method to start the connection. I have added my source code. Any form of help would be greatly appreciated. Thank you!


Code:
package com.patrickutz.wifiawarepublish;

import android.content.Context;
import android.net.wifi.aware.AttachCallback;
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.net.wifi.aware.PublishConfig;
import android.view.View;
import android.widget.TextView;



public class MainActivity extends AppCompatActivity {

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


    AttachCallback attachCallback = new AttachCallback();
    Handler handler = new Handler();

    // This is where I run into issues as Android Studio does not recognize the method attach
    WifiAwareSession publish =  attach(attachCallback, handler);


    private static final String AWARE_FILE_SHARE_SERVICE_NAME = "Test Publish";

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





    // Outputs the state of WifiAwareManager when press button (for now)
    String state_change = WifiAwareManager.ACTION_WIFI_AWARE_STATE_CHANGED;
    int data_init = WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR;
    int data_resp = WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER;

    public void showStatus(View view) {
        // Get the text views
        TextView showStateChangeTextView = (TextView) findViewById(R.id.stateChangeTextView);
        TextView showDataPathRoleInitTextView = (TextView) findViewById(R.id.dataPathRoleInitTextView);
        TextView showDataPathRoleRespTextView = (TextView) findViewById(R.id.dataPathRoleRespTextView);

        // Display the new values of current state in the text view.
        showStateChangeTextView.setText("State: " + state_change);
        showDataPathRoleInitTextView.setText("Data Initiator: " + Integer.toString(data_init));
        showDataPathRoleRespTextView.setText("Data Responder: " + Integer.toString(data_resp));

    }
}
 
attach() is a method provided by the WifiAwareManager class

https://developer.android.com/reference/android/net/wifi/aware/WifiAwareManager

You need to obtain an instance of it, to call that method. Try this

Code:
WifiAwareManager wifiAwareMgr = (WifiAwareManager)getSystemService(Context.WIFI_AWARE_SERVICE)
wifiAwareMgr.attach(.....)

This feature is very new, so unfortunately information about it is quite sparse.

Hi LV426,

Thanks for the response! I am wondering if that is a standard for instantiating objects since in Java it would be something like:

Code:
WifiAwareManager wifiAwareMgr = new WifiAwareManager(...);

Also, I am wondering how I would go about checking the compatibility of the device with WiFi Aware using the following code from the API:

Code:
context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_AWARE);

I am unsure how to create the object "context", and have tried multiple methods to no avail. Thanks!
 
1. Objects are usually instantiated by your code using 'new'. But in this case, WifieAwareManager is a system service, and the object has already been instantiated by the Android runtime. The method getSystemService() is a utility method, which returns the appropriate service to you, depending on the method parameters.

2. getPackageManager() is a method provided by the Context class. Your Activity is already a Context object, as it's a subclass of Context (indirectly). Therefore it can directly invoke that method. So this will work from anywhere in your MainActivity code.

Code:
getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_AWARE);
 
1. Objects are usually instantiated by your code using 'new'. But in this case, WifieAwareManager is a system service, and the object has already been instantiated by the Android runtime. The method getSystemService() is a utility method, which returns the appropriate service to you, depending on the method parameters.

2. getPackageManager() is a method provided by the Context class. Your Activity is already a Context object, as it's a subclass of Context (indirectly). Therefore it can directly invoke that method. So this will work from anywhere in your MainActivity code.

Code:
getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_AWARE);

I see! However, I realized that if I try to invoke the method outside of my publish method, the app just crashes. I ended up putting it in my publish method and now it works fine.

Another issue I'd like to mention is that when I try to call the isAvailable() method on my wifiAwareManager object, I get an error saying that it is a "null object reference". I have no idea why this is occurring as I properly instantiated the object. I have attached my updated (and polished) code along with the debug log. Thank you again for all the help so far!

Debug Log:

Code:
06/26 12:46:31: Launching app
$ adb shell am start -n "com.patrickutz.wifiawarepublish/com.patrickutz.wifiawarepublish.MainActivity" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER
Client not ready yet..Waiting for process to come online
Waiting for process to come online
Connected to process 12917 on device google-pixel-FA68R0302516
Capturing and displaying logcat messages from application. This behavior can be disabled in the "Logcat output" section of the "Debugger" settings page.
I/System.out: false
W/SystemServiceRegistry: No service published for: wifiaware
D/AndroidRuntime: Shutting down VM
E/AndroidRuntime: FATAL EXCEPTION: main
                  Process: com.patrickutz.wifiawarepublish, PID: 12917
                  java.lang.IllegalStateException: Could not execute method for android:onClick
                      at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:390)
                      at android.view.View.performClick(View.java:6294)
                      at android.view.View$PerformClick.run(View.java:24770)
                      at android.os.Handler.handleCallback(Handler.java:790)
                      at android.os.Handler.dispatchMessage(Handler.java:99)
                      at android.os.Looper.loop(Looper.java:164)
                      at android.app.ActivityThread.main(ActivityThread.java:6494)
                      at java.lang.reflect.Method.invoke(Native Method)
                      at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
                   Caused by: java.lang.reflect.InvocationTargetException
                      at java.lang.reflect.Method.invoke(Native Method)
                      at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:385)
                      at android.view.View.performClick(View.java:6294)
                      at android.view.View$PerformClick.run(View.java:24770)
                      at android.os.Handler.handleCallback(Handler.java:790)
                      at android.os.Handler.dispatchMessage(Handler.java:99)
                      at android.os.Looper.loop(Looper.java:164)
                      at android.app.ActivityThread.main(ActivityThread.java:6494)
                      at java.lang.reflect.Method.invoke(Native Method)
                      at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
                   Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.net.wifi.aware.WifiAwareManager.isAvailable()' on a null object reference
                      at com.patrickutz.wifiawarepublish.MainActivity.publish(MainActivity.java:52)
                      at java.lang.reflect.Method.invoke(Native Method)
                      at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:385)
                      at android.view.View.performClick(View.java:6294)
                      at android.view.View$PerformClick.run(View.java:24770)
                      at android.os.Handler.handleCallback(Handler.java:790)
                      at android.os.Handler.dispatchMessage(Handler.java:99)
                      at android.os.Looper.loop(Looper.java:164)
                      at android.app.ActivityThread.main(ActivityThread.java:6494)
                      at java.lang.reflect.Method.invoke(Native Method)
                      at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
Application terminated.


My code:

Java:
package com.patrickutz.wifiawarepublish;

import android.content.Context;
import android.content.pm.PackageManager;
import android.net.wifi.aware.AttachCallback;
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.net.wifi.aware.PublishConfig;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;


public class MainActivity extends AppCompatActivity {

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

    // Constant values of WifiAwareManager
    String state_change = WifiAwareManager.ACTION_WIFI_AWARE_STATE_CHANGED;
    int data_init = WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR;
    int data_resp = WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER;

    public void publish(View view) {

        // Check whether or not device supports WiFi Aware
        boolean hasWiFiAware = getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_AWARE);

        // Toast myToast = Toast.makeText(this, message, duration);
        // Messages for whether or not device has WiFi Aware
        Toast hasAware = Toast.makeText(this, "WiFi Aware Supported", Toast.LENGTH_SHORT);
        Toast noAware = Toast.makeText(this, "WiFi Aware Unsupported", Toast.LENGTH_SHORT);

        if (hasWiFiAware) {
            hasAware.show();
        } else {
            noAware.show();
        }

        System.out.println(hasWiFiAware);

        // Create WiFiAwareManager object
        WifiAwareManager wifiAwareManager = (WifiAwareManager)getSystemService(Context.WIFI_AWARE_SERVICE);

        // Check if WiFi Aware is available
        boolean awareAvailable = wifiAwareManager.isAvailable();

        // Messages for whether or not WiFi Aware is available
        Toast isAvailable = Toast.makeText(this, "WiFi Aware Supported", Toast.LENGTH_SHORT);
        Toast notAvailable = Toast.makeText(this, "WiFi Aware Unsupported", Toast.LENGTH_SHORT);

        if (awareAvailable) {
            isAvailable.show();
        } else {
            notAvailable.show();
        }

//        AttachCallback attachCallback = new AttachCallback();
//        Handler handler = new Handler();
//
//        wifiAwareManager.attach(attachCallback, handler);


//        private static final String AWARE_FILE_SHARE_SERVICE_NAME = "Test Publish";
//        PublishConfig config = new PublishConfig.Builder()
//                .setServiceName(AWARE_FILE_SHARE_SERVICE_NAME)
//                .build();


        // Get the text views
        TextView showStateChangeTextView = (TextView) findViewById(R.id.stateChangeTextView);
        TextView showDataPathRoleInitTextView = (TextView) findViewById(R.id.dataPathRoleInitTextView);
        TextView showDataPathRoleRespTextView = (TextView) findViewById(R.id.dataPathRoleRespTextView);

        // Display the new values of current state in the text view.
        showStateChangeTextView.setText("State: " + state_change);
        showDataPathRoleInitTextView.setText("Data Initiator: " + Integer.toString(data_init));
        showDataPathRoleRespTextView.setText("Data Responder: " + Integer.toString(data_resp));

    }
}
 
This line

Code:
WifiAwareManager wifiAwareManager = (WifiAwareManager)getSystemService(Context.WIFI_AWARE_SERVICE);

returned null. WIFI_AWARE_SERVICE is only available on API level 26 (Android 8.0)
What version of Android have you deployed the app to?
 
This line

Code:
WifiAwareManager wifiAwareManager = (WifiAwareManager)getSystemService(Context.WIFI_AWARE_SERVICE);

returned null. WIFI_AWARE_SERVICE is only available on API level 26 (Android 8.0)
What version of Android have you deployed the app to?

My Pixel (the phone I deployed the app to) is running version 8.1.0. Also weird how the method to check whether or not the phone supports WiFi Aware:

Code:
boolean hasWiFiAware = getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_AWARE);

returns false even though my phone is clearly supported. I get false when I run the code on the emulator (of a Pixel 2 XL) as well.
 
All your tests so far indicate that WiFi Aware isn't supported on this device. Surprising really. Maybe they plan to enable the feature in a future update.
 
All your tests so far indicate that WiFi Aware isn't supported on this device. Surprising really. Maybe they plan to enable the feature in a future update.
I agree however it is really weird since the documentation says that WiFi Aware is available on Android 8.0 and above and on the Pixel. I will send an email to Google detailing the issue. Also, I am wondering if you have any idea as to why I get the NullPointerException with the WifiAwareManager and WifiAwareSession objects. Do you think it has to do with the lack of support? Let me know, thank you.
 
What documentation says it's available on the Pixel 2 XL? Do you have a link?
 
What documentation says it's available on the Pixel 2 XL? Do you have a link?
**UPDATE**
So all along I have been running the code on my Pixel (running Android 8.1.0) yet I just tried it on a Pixel 2 XL and now I do not get the NullPointerException and my methods for testing WiFi Aware availability return true! Seems to be that it is not supported on the original Pixel and the hardware check methods were causing the app to crash (crazy!). I attached a picture showing the true returns for both availability and support when the button is pressed. However, now I am wondering if I am calling the attach() method correctly since I am just passing in objects of AttachCallback and Handler that I instantiated with empty constructors. The instructions from the API state that after I call the attach() method, the system executes the onAttached() callback and provides a WifiAwareSession object that the app will use for all further session operations. However I am wondering how I can obtain this WifiAwareSession object and what it means that the onAttached() callback is executed. Thank you. (my current code is below)

Code:
package com.patrickutz.wifiawarepublish;

import android.content.Context;
import android.content.pm.PackageManager;
import android.net.wifi.aware.AttachCallback;
import android.net.wifi.aware.DiscoverySessionCallback;
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.net.wifi.aware.PublishConfig;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;


public class MainActivity extends AppCompatActivity {

    // Variables
    private static final String AWARE_FILE_SHARE_SERVICE_NAME = "Test Publish"; // Name for publish service
    private Handler mHandler; // handler that gets info


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

    public void publish(View view) {

        // Check whether or not device supports WiFi Aware
        boolean hasWiFiAware = getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_AWARE);

        // Toast myToast = Toast.makeText(this, message, duration);
        // Messages for whether or not device has WiFi Aware
        Toast hasAware = Toast.makeText(this, "WiFi Aware Supported", Toast.LENGTH_SHORT);
        Toast noAware = Toast.makeText(this, "WiFi Aware Unsupported", Toast.LENGTH_SHORT);

        if (hasWiFiAware) {
            hasAware.show();
        } else {
            noAware.show();
        }

        System.out.println(hasWiFiAware);

        // Create WiFiAwareManager object
        WifiAwareManager wifiAwareManager = (WifiAwareManager)getSystemService(Context.WIFI_AWARE_SERVICE);

        // Check if WiFi Aware is available
        boolean awareAvailable = wifiAwareManager.isAvailable();
        // Messages for whether or not WiFi Aware is available
        TextView showAvailabilityTextView = (TextView) findViewById(R.id.availabilityTextView);
        if (awareAvailable) {
            showAvailabilityTextView.setText("WiFi Aware Available");
        } else {
            showAvailabilityTextView.setText("WiFi Aware Unavailable");
        }


        // Start WiFi Aware
        AttachCallback attachCallback = new AttachCallback();
        wifiAwareManager.attach(attachCallback, mHandler);



        // Start Publish Session
//        PublishConfig config = new PublishConfig.Builder()
//                .setServiceName(AWARE_FILE_SHARE_SERVICE_NAME)
//                .build();

//        DiscoverySessionCallback callback = new DiscoverySessionCallback();


//        wifiAwareSession.publish(config, callback, mHandler);



        // Get the text views
        TextView showStateChangeTextView = (TextView) findViewById(R.id.stateChangeTextView);
        TextView showDataPathRoleInitTextView = (TextView) findViewById(R.id.dataPathRoleInitTextView);
        TextView showDataPathRoleRespTextView = (TextView) findViewById(R.id.dataPathRoleRespTextView);

        // Constant values of WifiAwareManager
        String state_change = WifiAwareManager.ACTION_WIFI_AWARE_STATE_CHANGED;
        int data_init = WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR;
        int data_resp = WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER;

        // Display the new values of current state in the text view.
        showStateChangeTextView.setText("State: " + state_change);
        showDataPathRoleInitTextView.setText("Data Initiator: " + Integer.toString(data_init));
        showDataPathRoleRespTextView.setText("Data Responder: " + Integer.toString(data_resp));

    }
}
 

Attachments

  • Screenshot_20180627-142748.png
    Screenshot_20180627-142748.png
    308.5 KB · Views: 329
The hardware check methods didn't cause the app to crash on the Pixel. Your code trying to use a null object caused the crash.

In the above code, your mHandler is declared, but never assigned a created object, so will be null. However, this may not be a problem, as the documentation states

"handler Handler: The Handler on whose thread to execute the callbacks of the attachCallback object. If a null is provided then the application's main thread will be used."

But let's keep it simple to start with, and don't worry about the handler parameter. Simply use a null value:

Code:
wifiAwareManager.attach(attachCallback, null);

You do realise that you're meant to write a class which extends AttachCallback? The default method on this class does absolutely nothing. Here it is:

Code:
public class AttachCallback {
    /**
     * Called when Aware attach operation
     * {@link WifiAwareManager#attach(AttachCallback, android.os.Handler)}
     * is completed and that we can now start discovery sessions or connections.
     *
     * @param session The Aware object on which we can execute further Aware operations - e.g.
     *                discovery, connections.
     */
    public void onAttached(WifiAwareSession session) {
        /* empty */
    }

    /**
     * Called when Aware attach operation
     * {@link WifiAwareManager#attach(AttachCallback, android.os.Handler)} failed.
     */
    public void onAttachFailed() {
        /* empty */
    }
}

You can see it literally does nothing in those callback methods. You're meant to provide your own class to do something useful:

Code:
public class myAttachCallback extends AttachCallback {
 // Provide method implementations
 ...
}
 
I've got to say this is particularly bad design by Google. AttachCallback should be an INTERFACE, thereby forcing the developer to provide an implementing class. Or it should be declared as ABSTRACT, which would result in the same effect. What the hell were they thinking?! I'm quite surprised.
 
Yes, I am very disappointed with the documentation of WiFi Aware. So in that case do I have to create a separate class that extends AttachCallback and make my own constructor for it? And then I would have to instantiate an object of that class that I made and pass it to the attach() method of my WifiAwareManager object (along with null for Handler)? But even after all that, how do I create the WifiAwareSession object? Sorry that I'm a bit confused. I've coded in Java for two years but never on Android's platform. Again, thank you for all the help so far!
 
Yes you need to create your version of AttachCallback.
You don't create the WifiAwareSession object. That is given to you in the onAttach() method call.
 
Ok, so I have made an implementation of the AttachedCallback class called AttachedCallbackExt yet am unsure what to put in the methods. The onAttached() method is supposed to be called once the attach() method is completed. However, the onAttached() method takes a WifiAwareSession object so that means I would have to create a WifiAwareSession object after I call the attach() method and then pass that object to the onAttached() method of the AttachCallback object. An example of what I mean is down below along with my AttachCallbackExt class.

Is this what I am supposed to do? :

Code:
// Start WiFi Aware
        AttachCallbackExt attachCallback = new AttachCallbackExt();
        wifiAwareManager.attach(attachCallback, null);
        // somehow create WifiAwareSession object called session
        attachCallback.onAttached(session);

AttachCallbackExt:

Code:
package com.patrickutz.wifiawarepublish;

import android.net.wifi.aware.AttachCallback;
import android.net.wifi.aware.WifiAwareSession;

public class AttachCallbackExt extends AttachCallback {

    public AttachCallbackExt() {
        System.out.println("AttachCallback object created");
    }

    /**
     * Called when Aware attach operation
     * {@link WifiAwareManager#attach(AttachCallback, android.os.Handler)}
     * is completed and that we can now start discovery sessions or connections.
     *
     * @param session The Aware object on which we can execute further Aware operations - e.g.
     *                discovery, connections.
     */
    @Override
    public void onAttached(WifiAwareSession session) {

        System.out.println("Attach operation completed and can now start discovery sessions");

    }

    /**
     * Called when Aware attach operation
     * {@link WifiAwareManager#attach(AttachCallback, android.os.Handler)} failed.
     */
    @Override
    public void onAttachFailed() {
        System.out.println("Attach operation failed");

    }
}
 
First thing is, you cannot debug an Android application using System.out.println(). It's completely ineffective.

Debugging is done by running the app in debug mode, and setting breakpoints in the code. Or failing that, use Log.d() statements in your code, which will make the output show up in the Logcat view.

// Start WiFi Aware
AttachCallbackExt attachCallback = new AttachCallbackExt();
wifiAwareManager.attach(attachCallback, null);
// somehow create WifiAwareSession object called session
attachCallback.onAttached(session);

No. This is wrong. Your code does not call the onAttached() method. It's a callback, used by the Android runtime, to tell your app that the WifiAwareSession is available - which it passes to you as the parameter. Your code does not create the WifiAwareSession object.
 
Ok, yes that makes sense. I have revised my code below and am wondering what to do to get that WifiAwareSession object.

Code:

Java:
        // Start WiFi Aware
        AttachCallbackExt attachCallback = new AttachCallbackExt();
        wifiAwareManager.attach(attachCallback, null);
        WifiAwareSession session = // what should I put here?
 
I'm obviously not explaining this clearly enough.

Look at the class you defined called AttachCallbackExt. It has the following method

Code:
public void onAttached(WifiAwareSession session)

This method will be called by the Android runtime framework automatically, by the WifiAwareManager, when it has created a WifiAwareSession object for you.

You do not create the WifiAwareSession object, it is created for you.

So to answer your question

Code:
WifiAwareSession session = // what should I put here?

Delete this line from your code.

Whatever you want to do with WifiAwareSession will happen in the onAttached() method.
 
I'm obviously not explaining this clearly enough.

Look at the class you defined called AttachCallbackExt. It has the following method

Code:
public void onAttached(WifiAwareSession session)

This method will be called by the Android runtime framework automatically, by the WifiAwareManager, when it has created a WifiAwareSession object for you.

You do not create the WifiAwareSession object, it is created for you.

So to answer your question

Code:
WifiAwareSession session = // what should I put here?

Delete this line from your code.

Whatever you want to do with WifiAwareSession will happen in the onAttached() method.

Ok after sometime reading up more documentation and experimenting, I fixed my code and also wrote the code for my Subscriber app. At this point, I start my publishing on one device and then start my subscription service on another device which is connected to the debugger. I implemented some Log.d tags to see what is going on and can successfully say that the subscriber is able to both start and recognize the publisher (super happy about this)! At this point I just want to send a simple message to the publisher and the documentation states that you need to call the sendMessage() method on a DiscoverySession object (this is done on the subscriber side first). I am wondering how you are able to call this method once onServiceDiscovered() is executed. I have attached a picture of the documentation along with my code for the subscriber where the DiscoverySession object is. Thank you again for the help thus far!

Code:
public class AttachCallbackExt extends AttachCallback {

    // Variables
    private static final String AWARE_FILE_SHARE_SERVICE_NAME = "WiFiAwareTest"; // Name for publish service

    public AttachCallbackExt() {
        Log.d("Object Created", "AttachCallback object created");
    }

    /**
     * Called when Aware attach operation
     * {@link WifiAwareManager#attach(AttachCallback, android.os.Handler)}
     * is completed and that we can now start discovery sessions or connections.
     *
     * @param session The Aware object on which we can execute further Aware operations - e.g.
     *                discovery, connections.
     */
    @TargetApi(Build.VERSION_CODES.O)
    @RequiresApi(api = Build.VERSION_CODES.O)
    @Override
    public void onAttached(WifiAwareSession mAwaresession) {
        Log.d("Method called", "Attach operation completed and can now start discovery sessions");

        // Start Subscribe Session
        SubscribeConfig config = new SubscribeConfig.Builder()
                .setServiceName(AWARE_FILE_SHARE_SERVICE_NAME)
                .build();

        mAwaresession.subscribe(config, new DiscoverySessionCallbackExt() {
            @Override
            public void onSubscribeStarted(SubscribeDiscoverySession session) {
                Log.d("Method Called", "onSubscribeStarted");
            }
            @Override
            public void onServiceDiscovered(PeerHandle peerHandle, byte[] serviceSpecificInfo,
                                            List<byte[]> matchFilter) {
                Log.d("Method Called", "onServiceDiscovered");
            }}, null);
    }

    /**
     * Called when Aware attach operation
     * {@link WifiAwareManager#attach(AttachCallback, android.os.Handler)} failed.
     */
    @Override
    public void onAttachFailed() {
        Log.d("Method called", "Attach operation failed");

    }
}
 

Attachments

  • Screen Shot 2018-06-28 at 3.33.08 PM.png
    Screen Shot 2018-06-28 at 3.33.08 PM.png
    133.5 KB · Views: 374
Looks like sending a message is supposed to happen in onServiceDiscovered(). As the docs say:

"At this point, your subscription waits for matching publishers to come into Wi-Fi range. When this happens, the system executes the onServiceDiscovered() callback method. You can use the PeerHandle argument from this callback to send a message or create a connection to that publisher."
**UPDATE**

I have made much progress on the app and am now able to both send and receive messages on both ends. However, at this point I would like to display a certain TextView when my subscriber finds the publisher. The issue is that this happens in the onServiceDiscovered() within the onAttached() method of my AttachCallbackExt class. I am unable to access my textviews or toast since I do not have the proper context in the AttachCallbackExt class. Let me know if you have any idea as to how I can either use TextViews directly in the AttachCallbackExt class or instead call a method from my MainActivity class. My code for both classes are down below. Thanks!

MainActivity class:
Code:
package com.patrickutz.wifiawaresubscribe;

import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.wifi.aware.WifiAwareManager;
import android.provider.Settings;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    //Variables
    AttachCallbackExt mainAttachCallback = new AttachCallbackExt();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // If location permission is not enabled location settings will open up
        // User then needs to enable location permissions for the app
        if (ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.ACCESS_COARSE_LOCATION)
                != PackageManager.PERMISSION_GRANTED) {
            Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
            startActivity(intent);
        }

        // Check whether or not device supports WiFi Aware and display status as Toast message
        boolean hasWiFiAware = getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_AWARE);
        Toast hasAware = Toast.makeText(this, "WiFi Aware Supported", Toast.LENGTH_SHORT);
        Toast noAware = Toast.makeText(this, "WiFi Aware Unsupported. Please Exit the Program.", Toast.LENGTH_LONG);

        if (hasWiFiAware) {
            hasAware.show();
        } else {
            noAware.show();
        }
    }

    public void subscribe(View view) {

        // Create WiFiAwareManager object
        WifiAwareManager wifiAwareManager = (WifiAwareManager)getSystemService(Context.WIFI_AWARE_SERVICE);

        // Create TextView objects to display status
        TextView status1 = (TextView) findViewById(R.id.statusTextView1);
        TextView status2 = (TextView) findViewById(R.id.statusTextView2);
        TextView status3 = (TextView) findViewById(R.id.statusTextView3);

        // Check if WiFi Aware is available
        boolean awareAvailable = wifiAwareManager.isAvailable();
        if (awareAvailable) {
            status1.setText("Wifi Aware Available");
            status2.setText("Searching for");
            status3.setText("Publishers...");
        } else {
            status1.setText("Wifi Aware");
            status2.setText("Not Available");
            status3.setText("Please Turn on WiFi");
        }

        // Start WiFi Aware
        AttachCallbackExt attachCallback = new AttachCallbackExt();
        wifiAwareManager.attach(attachCallback, null);
        mainAttachCallback = attachCallback;
    }

    public void showMessageReceived(View view) {

        // Create TextView objects to display status
        TextView status1 = (TextView) findViewById(R.id.statusTextView1);
        TextView status2 = (TextView) findViewById(R.id.statusTextView2);
        TextView status3 = (TextView) findViewById(R.id.statusTextView3);

        if (mainAttachCallback.getMessageReceived() == null) {
            //do nothing
            Log.d("lol", "Nothing happened");
        } else {
            Log.d("lol", new String(mainAttachCallback.getMessageReceived()));
            String messageReceived = new String(mainAttachCallback.getMessageReceived());
            status1.setText("Message Received");
            status2.setText(" ' " + messageReceived + " ' ");
            status3.setText("");
        }
    }

    public void stopPublish(View view) {
        Toast endService = Toast.makeText(this, "Subscriber Service Ended", Toast.LENGTH_LONG);
        endService.show();
        finish();
        System.exit(1);
    }
}


AttachCallbackExt class:

Code:
package com.patrickutz.wifiawaresubscribe;

import android.annotation.TargetApi;
import android.content.Context;
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.WifiAwareSession;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.util.Log;

import java.util.List;

public class AttachCallbackExt extends AttachCallback {

    // Variables
    private static final String AWARE_FILE_SHARE_SERVICE_NAME = "WiFiAwareTest"; // Name for publish service
    private byte [] messageReceived = null;

    public AttachCallbackExt() {
        Log.d("Object Created", "AttachCallback object created");
    }

    /**
     * Called when Aware attach operation
     * {@link WifiAwareManager#attach(AttachCallback, android.os.Handler)}
     * is completed and that we can now start discovery sessions or connections.
     *
     * @param session The Aware object on which we can execute further Aware operations - e.g.
     *                discovery, connections.
     */
    @TargetApi(Build.VERSION_CODES.O)
    @RequiresApi(api = Build.VERSION_CODES.O)
    @Override
    public void onAttached(final WifiAwareSession mAwaresession) {
        Log.d("Method called", "Attach operation completed and can now start discovery sessions");
        final byte[] messageSend = new byte[1];
        messageSend[0] = 104;

        // Start Subscribe Session
        SubscribeConfig config = new SubscribeConfig.Builder()
                .setServiceName(AWARE_FILE_SHARE_SERVICE_NAME)
                .build();

        mAwaresession.subscribe(config, new DiscoverySessionCallback() {

            SubscribeDiscoverySession mainSession;

            @Override
            public void onSubscribeStarted(SubscribeDiscoverySession session) {
                Log.d("Method Called", "onSubscribeStarted");
                mainSession = session;
            }
            @Override
            public void onServiceDiscovered(PeerHandle peerHandle, byte[] serviceSpecificInfo,
                                            List<byte[]> matchFilter) {
                Log.d("Method Called", "onServiceDiscovered");
                mainSession.sendMessage(peerHandle, 1, messageSend);
            }
            @Override
            public void onMessageReceived(PeerHandle peerHandle, byte[] messageFromPub) {
                Log.d("Method Called", "onMessageReceived");
                Log.d("Messaged Received is", new String(messageFromPub));
                messageReceived = messageFromPub;
            }}, null);
    }

    /**
     * Called when Aware attach operation
     * {@link WifiAwareManager#attach(AttachCallback, android.os.Handler)} failed.
     */
    @Override
    public void onAttachFailed() {
        Log.d("Method called", "Attach operation failed");
    }

    public byte[] getMessageReceived() {
        return messageReceived;
    }
}
 
You can pass in your MainActivity (Context) object to the constructor of the AttachCallbackExt class

Code:
AttachCallbackExt attachCallback = new AttachCallbackExt(this);

Store this value as a class variable

Code:
public class AttachCallbackExt extends AttachCallback {
  private MainActivity mActivity;

  ...
  public AttachCallbackExt(Context activity) {
    this.mActivity = activity;
  }
  ...
}

And then you call a method on the Activity class to set the TextView message

Code:
onServiceDiscovered() {
  ...
  mActivity.setText("hello world");
  ...
}
 
You can pass in your MainActivity (Context) object to the constructor of the AttachCallbackExt class

Code:
AttachCallbackExt attachCallback = new AttachCallbackExt(this);

Store this value as a class variable

Code:
public class AttachCallbackExt extends AttachCallback {
  private MainActivity mActivity;

  ...
  public AttachCallbackExt(Context activity) {
    this.mActivity = activity;
  }
  ...
}

And then you call a method on the Activity class to set the TextView message

Code:
onServiceDiscovered() {
  ...
  mActivity.setText("hello world");
  ...
}
Fantastic, thank you again for all your help!
 
Hey! Goood work with the kind of scarce documentation on this. Please share your publish logic as well as I'm not sure how we could get WifiAwareSession's instance as in the official doc (although I did read over and over that its created in onAttached()'s callback).
 
Back
Top Bottom