Ramz
Ramz

Reputation: 7164

Transfer Data between Android devices using wifi direct?

I have recently implement wifi direct into my project,my aim is pass string value between two wifidirect connected devices when some of my app condition satisfies.right now i have listed all peers and also made connection between the selected peer.what my idea is to pass a json file between the devices.so before try to execute that idea i try to pass a image file between two devices.i followed the steps from the android wifidirect tutorial.listing peers and the connection between the peers is success full but i cant pass the data between the devices.the follwing is my code. FileTransferService.java

package jing.app.directwifi;

import android.app.IntentService;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
 import android.util.Log;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;


/**
 * A service that process each file transfer request i.e Intent by opening a
 * socket connection with the WiFi Direct Group Owner and writing the file
 */
public class FileTransferService extends IntentService {

private static final int SOCKET_TIMEOUT = 5000;
public static final String ACTION_SEND_FILE = "jing.app.directwifi.SEND_FILE";
public static final String EXTRAS_FILE_PATH = "file_url";
public static final String EXTRAS_GROUP_OWNER_ADDRESS = "go_host";
public static final String EXTRAS_GROUP_OWNER_PORT = "go_port";

public FileTransferService(String name) {
    super(name);
}

public FileTransferService() {
    super("FileTransferService");
}

/*
 * (non-Javadoc)
 * @see android.app.IntentService#onHandleIntent(android.content.Intent)
 */
@Override
protected void onHandleIntent(Intent intent) {

    Context context = getApplicationContext();
    if (intent.getAction().equals(ACTION_SEND_FILE)) {
        String fileUri = intent.getExtras().getString(EXTRAS_FILE_PATH);
        String host = intent.getExtras().getString(EXTRAS_GROUP_OWNER_ADDRESS);
        Socket socket = new Socket();
        int port = intent.getExtras().getInt(EXTRAS_GROUP_OWNER_PORT);

        try {
           // Log.d(WiFiDirectActivity.TAG, "Opening client socket - ");
            socket.bind(null);
            socket.connect((new InetSocketAddress(host, port)), SOCKET_TIMEOUT);

            Log.d("connected", "Client socket - " + socket.isConnected());
            OutputStream stream = socket.getOutputStream();
            ContentResolver cr = context.getContentResolver();
            InputStream is = null;
            try {
                is = cr.openInputStream(Uri.parse(fileUri));
            } catch (FileNotFoundException e) {
                Log.d("exp", e.toString());
            }
           MainActivity.copyFile(is, stream);
            Log.d("exp" ,"Client: Data written");
        } catch (IOException e) {
            Log.e("exp", e.getMessage());
        } finally {
            if (socket != null) {
                if (socket.isConnected()) {
                    try {
                        socket.close();
                    } catch (IOException e) {
                        // Give up
                        e.printStackTrace();
                    }
                }
            }
        }

    }
}
}

Main Activity.java

package jing.app.directwifi;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Collection;





import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.net.wifi.p2p.WifiP2pConfig;
import android.net.wifi.p2p.WifiP2pDevice;
 import android.net.wifi.p2p.WifiP2pDeviceList;
import android.net.wifi.p2p.WifiP2pInfo;
import android.net.wifi.p2p.WifiP2pManager;
import android.net.wifi.p2p.WifiP2pManager.ActionListener;
import android.net.wifi.p2p.WifiP2pManager.Channel;
import android.net.wifi.p2p.WifiP2pManager.ConnectionInfoListener;
import android.net.wifi.p2p.WifiP2pManager.PeerListListener;
import android.os.AsyncTask;
import android.os.Bundle;
 import android.os.Environment;
import android.provider.Settings;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity implements OnClickListener,   android.content.DialogInterface.OnClickListener, ConnectionInfoListener {

private WifiP2pManager mManager;
private Channel mChannel;
private BroadcastReceiver mReceiver;
private IntentFilter mIntentFilter;

private Button mDiscover;
private TextView mDevices;
public ArrayAdapter mAdapter;
private ArrayList<WifiP2pDevice> mDeviceList = new ArrayList<WifiP2pDevice>();
protected static final int CHOOSE_FILE_RESULT_CODE = 20;
int flag=0;
@Override
protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mDiscover = (Button) findViewById(R.id.discover);
    mDiscover.setOnClickListener(this);

    mDevices = (TextView) findViewById(R.id.peers);

    mManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
    mChannel = mManager.initialize(this, getMainLooper(), null);
    mReceiver = new WiFiDirectReceiver(mManager, mChannel, this);

    mIntentFilter = new IntentFilter();
    mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
    mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
    mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
    mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);


}

@Override
protected void onResume() {
    super.onResume();
    registerReceiver(mReceiver, mIntentFilter);
}

@Override
protected void onPause() {
    super.onPause();
    unregisterReceiver(mReceiver);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.activity_main, menu);
    return true;
}

private class WiFiDirectReceiver extends BroadcastReceiver {

    private WifiP2pManager mManager;
    private Channel mChannel;
    private MainActivity mActivity;

    public WiFiDirectReceiver(WifiP2pManager manager, Channel channel, MainActivity activity) {
        super();
        mManager = manager;
        mChannel = channel;
        mActivity = activity;
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();

        if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {

            int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);
            if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {
                   String title = "ANDROID_ID[" + getAndroid_ID() + "]";
                   title += "   MAC[" + getMACAddress() + "]";
                Toast.makeText(mActivity, "Wi-Fi Direct is enabled."+title, Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(mActivity, "Wi-Fi Direct is disabled.", Toast.LENGTH_SHORT).show();
            }

        } else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {

            if (mManager != null) {
                mManager.requestPeers(mChannel, new PeerListListener() {

                    @Override
                    public void onPeersAvailable(WifiP2pDeviceList peers) {
                        if (peers != null) {
                            mDeviceList.addAll(peers.getDeviceList());
                            ArrayList<String> deviceNames = new ArrayList<String>();
                            for (WifiP2pDevice device : mDeviceList) {
                                deviceNames.add(device.deviceName);
                            }
                            if (deviceNames.size() > 0) {
                                mAdapter = new ArrayAdapter<String>(mActivity, android.R.layout.simple_list_item_1, deviceNames);
                                if(flag==0)
                                {
                                    flag=1;
                                showDeviceListDialog();
                                }
                            } else {
                                Toast.makeText(mActivity, "Device list is empty.", Toast.LENGTH_SHORT).show();
                            }
                        }
                    }
                });
            }

        } else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {


        } else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) {

        }
    }

}

@Override
public void onClick(View v) {
    switch (v.getId()) {
    case R.id.discover:
        onDiscover();
        break;
    }
}

private void onDiscover() {
    mManager.discoverPeers(mChannel, new ActionListener() {

        @Override
        public void onSuccess() {
            Toast.makeText(MainActivity.this, "Discover peers successfully.", Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onFailure(int reason) {
            Toast.makeText(MainActivity.this, "Discover peers failed.", Toast.LENGTH_SHORT).show();
        }
    });
}

private void showDeviceListDialog() {
    DeviceListDialog deviceListDialog = new DeviceListDialog();
    deviceListDialog.show(getFragmentManager(), "devices");
}

private class DeviceListDialog extends DialogFragment {

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
        builder.setTitle("Select a device")
               .setSingleChoiceItems(mAdapter, 0, MainActivity.this)
               .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {

                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                    }

               });

        return builder.create();
    }

}

@Override
public void onClick(DialogInterface dialog, int which) {
    onDeviceSelected(which);
    dialog.dismiss();
}

private void onDeviceSelected(int which) {
    WifiP2pDevice device = mDeviceList.get(which);
    if (device == null) {
        return;
    }

    WifiP2pConfig config = new WifiP2pConfig();
    config.deviceAddress = device.deviceAddress;
    mManager.connect(mChannel, config, new ActionListener() {

        @Override
        public void onSuccess() {
            Toast.makeText(MainActivity.this, "Connected", Toast.LENGTH_SHORT).show();
              Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
              intent.setType("image/*");
              startActivityForResult(intent, CHOOSE_FILE_RESULT_CODE);
        }

        @Override
        public void onFailure(int reason) {
            Toast.makeText(MainActivity.this, "Failed to connect", Toast.LENGTH_SHORT).show();
        }
    });
}
/**
 * ANDROID_ID
 */
private String getAndroid_ID() {
    return Settings.Secure.getString(getContentResolver(), Settings.Secure.ANDROID_ID);
}

/**
 * Wi-Fi MAC
 */
private String getMACAddress() {
    WifiManager manager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
    WifiInfo wifiInfo = manager.getConnectionInfo();
    String mac = wifiInfo.getMacAddress();

    // After the group negotiation, we assign the group owner as the file
    // server. The file server is single threaded, single connection server
    // socket.

        new FileServerAsyncTask(getApplicationContext())
                .execute();





    return mac;
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {

    // User has picked an image. Transfer it to group owner i.e peer using
    // FileTransferService.
    Uri uri = data.getData();

  Log.d("intent", "Intent----------- " + uri);
    Intent serviceIntent = new Intent(MainActivity.this, FileTransferService.class);
    serviceIntent.setAction(FileTransferService.ACTION_SEND_FILE);
    serviceIntent.putExtra(FileTransferService.EXTRAS_FILE_PATH, uri.toString());
    serviceIntent.putExtra(FileTransferService.EXTRAS_GROUP_OWNER_ADDRESS,
            getMACAddress());
    serviceIntent.putExtra(FileTransferService.EXTRAS_GROUP_OWNER_PORT, 8988);
    startService(serviceIntent);
}
/**
 * A simple server socket that accepts connection and writes some data on
 * the stream.
 */
public static class FileServerAsyncTask extends AsyncTask<Void, Void, String> {

    private Context context;


    /**
     * @param context
     * @param statusText
     */
    public FileServerAsyncTask(Context context) {
        this.context = context;

    }

    @Override
    protected String doInBackground(Void... params) {
        try {
            System.out.println("insideeeeeeeeeeeeeeeeeeeeeeee");
            ServerSocket serverSocket = new ServerSocket(8988);
            Log.d("Server: Socket opened", "Server: Socket opened");
            Socket client = serverSocket.accept();
            Log.d("Server: connection done", "Server: connection done");
            final File f = new File(Environment.getExternalStorageDirectory() + "/"
                    + context.getPackageName() + "/wifip2pshared-" +   System.currentTimeMillis()
                    + ".jpg");

            File dirs = new File(f.getParent());
            if (!dirs.exists())
                dirs.mkdirs();
            f.createNewFile();

            Log.d("server: copying files ", "server: copying files " + f.toString());
            InputStream inputstream = client.getInputStream();
            copyFile(inputstream, new FileOutputStream(f));
            serverSocket.close();
            return f.getAbsolutePath();
        } catch (IOException e) {
            Log.e("exp", e.getMessage());
            System.out.println(":iooo:"+e);
            return null;
        }
    }

    /*
     * (non-Javadoc)
     * @see android.os.AsyncTask#onPostExecute(java.lang.Object)
     */
    @Override
    protected void onPostExecute(String result) {
        if (result != null) {

            Intent intent = new Intent();
            intent.setAction(android.content.Intent.ACTION_VIEW);
            intent.setDataAndType(Uri.parse("file://" + result), "image/*");
            context.startActivity(intent);
        }

    }

    /*
     * (non-Javadoc)
     * @see android.os.AsyncTask#onPreExecute()
     */
    @Override
    protected void onPreExecute() {

    }

}
public static boolean copyFile(InputStream inputStream, OutputStream out) {
    byte buf[] = new byte[1024];
    int len;
    long startTime=System.currentTimeMillis();

    try {
        while ((len = inputStream.read(buf)) != -1) {
            out.write(buf, 0, len);
        }
        out.close();
        inputStream.close();
        long endTime=System.currentTimeMillis()-startTime;
        Log.v("","Time taken to transfer all bytes is : "+endTime);

    } catch (IOException e) {
        Log.d("exp", e.toString());
        return false;
    }
    return true;
}

@Override
public void onConnectionInfoAvailable(WifiP2pInfo info) {
    // TODO Auto-generated method stub

    Toast.makeText(getApplicationContext(), "connectioninfoo", 3000).show();

}

}

Manifest

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="jing.app.directwifi"
android:versionCode="1"
android:versionName="1.0" >

<uses-sdk
    android:minSdkVersion="14"
    android:targetSdkVersion="16" />

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- Market filtering -->
<uses-feature
    android:name="android.hardware.wifi.direct"
    android:required="true" />

<application
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >
    <activity
        android:name="jing.app.directwifi.MainActivity"
        android:label="@string/app_name" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    <!-- Used for transferring files  after a successful connection -->
    <service
        android:name=".FileTransferService"
        android:enabled="true" />
</application>

</manifest>

These are files used in my code .form the tutorial i have found that

new FileServerAsyncTask(getApplicationContext()) .execute();

where the the incomming data is begin accepted so when i need to execute this asyn thread,so anyone help me in which portion i have made the mistake.how can i transfer the file between devices .

Upvotes: 3

Views: 26325

Answers (2)

Dipendra
Dipendra

Reputation: 1557

The android code from the demo wifi direct project is able to pass file is unidirectional. ie. you can send file from client to server only. You need furthur modifications to make it work in both direction.

EDIT 2:

For that you need to know the IP address of both connected peers. Use the following function which I made following various sources with my modifications wherever appropriate.

    public static String getIpAddress() {
    try {
        List<NetworkInterface> interfaces = Collections
                .list(NetworkInterface.getNetworkInterfaces());
        /*
         * for (NetworkInterface networkInterface : interfaces) { Log.v(TAG,
         * "interface name " + networkInterface.getName() + "mac = " +
         * getMACAddress(networkInterface.getName())); }
         */

        for (NetworkInterface intf : interfaces) {
            if (!getMACAddress(intf.getName()).equalsIgnoreCase(
                    Globals.thisDeviceAddress)) {
                // Log.v(TAG, "ignore the interface " + intf.getName());
                // continue;
            }
            if (!intf.getName().contains("p2p"))
                continue;

            Log.v(TAG,
                    intf.getName() + "   " + getMACAddress(intf.getName()));

            List<InetAddress> addrs = Collections.list(intf
                    .getInetAddresses());

            for (InetAddress addr : addrs) {
                // Log.v(TAG, "inside");

                if (!addr.isLoopbackAddress()) {
                    // Log.v(TAG, "isnt loopback");
                    String sAddr = addr.getHostAddress().toUpperCase();
                    Log.v(TAG, "ip=" + sAddr);

                    boolean isIPv4 = InetAddressUtils.isIPv4Address(sAddr);

                    if (isIPv4) {
                        if (sAddr.contains("192.168.49.")) {
                            Log.v(TAG, "ip = " + sAddr);
                            return sAddr;
                        }
                    }

                }

            }
        }

    } catch (Exception ex) {
        Log.v(TAG, "error in parsing");
    } // for now eat exceptions
    Log.v(TAG, "returning empty ip address");
    return "";
}

public static String getMACAddress(String interfaceName) {
        try {
            List<NetworkInterface> interfaces = Collections
                    .list(NetworkInterface.getNetworkInterfaces());

            for (NetworkInterface intf : interfaces) {
                if (interfaceName != null) {
                    if (!intf.getName().equalsIgnoreCase(interfaceName))
                        continue;
                }
                byte[] mac = intf.getHardwareAddress();
                if (mac == null)
                    return "";
                StringBuilder buf = new StringBuilder();
                for (int idx = 0; idx < mac.length; idx++)
                    buf.append(String.format("%02X:", mac[idx]));
                if (buf.length() > 0)
                    buf.deleteCharAt(buf.length() - 1);
                return buf.toString();
            }
        } catch (Exception ex) {
        } // for now eat exceptions
        return "";
        /*
         * try { // this is so Linux hack return
         * loadFileAsString("/sys/class/net/" +interfaceName +
         * "/address").toUpperCase().trim(); } catch (IOException ex) { return
         * null; }
         */
    }

Upvotes: 9

No8
No8

Reputation: 77

I think the way you initialize client makes the problem.

You need to call this

new FileServerAsyncTask(getApplicationContext()).execute();

after the connection is established and check if it's a client.

Now you are creating a client socket only if it is a server(group owner) and always when you call to get a MAC address.

So on the client side you are not intializing the socket and so not able to receive the file.

Once check the WifiDirect sample demo provided in the SDK, you may get more idea.

Upvotes: 1

Related Questions