mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2024-12-29 10:26:36 +01:00
more work on wifi direct
Now sends and receives a single packet more often than not. Disabled for non-DEBUG devices, and new permissions that are required are commented out so I don't accidentally ship before the sdk-23 permissions stuff makes additions less scary.
This commit is contained in:
parent
85c12d6a85
commit
154e428fa8
4 changed files with 225 additions and 48 deletions
|
@ -48,7 +48,11 @@
|
|||
<uses-permission android:name="android.permission.BLUETOOTH" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
|
||||
<uses-permission android:name="android.permission.READ_CONTACTS" />
|
||||
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
|
||||
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
|
||||
|
||||
<!-- Added for wifi-direct; don't ship until move to 23!!! -->
|
||||
<!-- <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> -->
|
||||
<!-- <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> -->
|
||||
|
||||
<uses-feature android:name="android.hardware.telephony"
|
||||
android:required = "false"
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/GitVersion.java
|
||||
BuildConstants.java
|
||||
GCMConsts.java
|
||||
nohup.out
|
||||
|
|
|
@ -22,56 +22,102 @@ package org.eehouse.android.xw4;
|
|||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Socket;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
public class BiDiSockWrap {
|
||||
interface Iface {
|
||||
void gotPacket( BiDiSockWrap socket, byte[] bytes );
|
||||
void onSocketClosed( BiDiSockWrap socket );
|
||||
void gotPacket( BiDiSockWrap wrap, byte[] bytes );
|
||||
void connectStateChanged( BiDiSockWrap wrap, boolean nowConnected );
|
||||
}
|
||||
|
||||
private Socket mSocket;
|
||||
private Iface mIface;
|
||||
private LinkedBlockingQueue<byte[]> mQueue;
|
||||
private Thread mReadThread;
|
||||
private Thread mWriteThread;
|
||||
private boolean mRunThreads;
|
||||
private boolean mActive;
|
||||
private InetAddress mAddress;
|
||||
private int mPort;
|
||||
|
||||
// For sockets that came from accept() on a ServerSocket
|
||||
public BiDiSockWrap( Socket socket, Iface iface )
|
||||
{
|
||||
init( socket, iface );
|
||||
mIface = iface;
|
||||
init( socket );
|
||||
}
|
||||
|
||||
// For creating sockets that will connect to a remote ServerSocket
|
||||
public BiDiSockWrap( String address, int port, Iface iface )
|
||||
// For creating sockets that will connect to a remote ServerSocket. Must
|
||||
// call connect() afterwards.
|
||||
public BiDiSockWrap( InetAddress address, int port, Iface iface )
|
||||
{
|
||||
Socket socket = null;
|
||||
try {
|
||||
socket = new Socket( address, port );
|
||||
} catch ( java.net.UnknownHostException uhe ) {
|
||||
Assert.fail();
|
||||
} catch ( IOException uhe ) {
|
||||
Assert.fail();
|
||||
}
|
||||
if ( null != socket ) {
|
||||
init( socket, iface );
|
||||
}
|
||||
mIface = iface;
|
||||
mAddress = address;
|
||||
mPort = port;
|
||||
}
|
||||
|
||||
public BiDiSockWrap connect()
|
||||
{
|
||||
mActive = true;
|
||||
new Thread( new Runnable() {
|
||||
public void run() {
|
||||
long waitMillis = 1000;
|
||||
while ( mActive ) {
|
||||
try {
|
||||
Thread.sleep( waitMillis );
|
||||
DbgUtils.logd( getClass(), "trying to connect..." );
|
||||
Socket socket = new Socket( mAddress, mPort );
|
||||
DbgUtils.logd( getClass(), "connected!!!" );
|
||||
init( socket );
|
||||
mIface.connectStateChanged( BiDiSockWrap.this, true );
|
||||
break;
|
||||
} catch ( java.net.UnknownHostException uhe ) {
|
||||
DbgUtils.logex( uhe );
|
||||
} catch ( IOException ioe ) {
|
||||
DbgUtils.logex( ioe );
|
||||
} catch ( InterruptedException ie ) {
|
||||
DbgUtils.logex( ie );
|
||||
}
|
||||
waitMillis = Math.min( waitMillis * 2, 1000 * 60 );
|
||||
}
|
||||
}
|
||||
} ).start();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public Socket getSocket() { return mSocket; }
|
||||
|
||||
public boolean isConnected() { return null != getSocket(); }
|
||||
|
||||
public void send( String packet )
|
||||
{
|
||||
try {
|
||||
send( packet.getBytes( "UTF-8" ) );
|
||||
} catch ( java.io.UnsupportedEncodingException uee ) {
|
||||
DbgUtils.logex( uee );
|
||||
}
|
||||
}
|
||||
|
||||
public void send( JSONObject obj )
|
||||
{
|
||||
send( obj.toString() );
|
||||
}
|
||||
|
||||
public void send( byte[] packet )
|
||||
{
|
||||
Assert.assertNotNull( packet );
|
||||
mQueue.add(packet);
|
||||
}
|
||||
|
||||
private void init( Socket socket, Iface iface )
|
||||
private void init( Socket socket )
|
||||
{
|
||||
mSocket = socket;
|
||||
mIface = iface;
|
||||
mQueue = new LinkedBlockingQueue<byte[]>();
|
||||
startThreads();
|
||||
}
|
||||
|
@ -79,13 +125,14 @@ public class BiDiSockWrap {
|
|||
private void closeSocket()
|
||||
{
|
||||
mRunThreads = false;
|
||||
mActive = false;
|
||||
try {
|
||||
mSocket.close();
|
||||
} catch ( IOException ioe ) {
|
||||
DbgUtils.logex( ioe );
|
||||
}
|
||||
mIface.onSocketClosed( this );
|
||||
send( new byte[0] );
|
||||
mIface.connectStateChanged( this, false );
|
||||
send( (byte[])null );
|
||||
}
|
||||
|
||||
private void startThreads()
|
||||
|
@ -99,9 +146,10 @@ public class BiDiSockWrap {
|
|||
= new DataOutputStream( mSocket.getOutputStream() );
|
||||
while ( mRunThreads ) {
|
||||
byte[] packet = mQueue.take();
|
||||
DbgUtils.logd( getClass(), "write thread got packet of len %d",
|
||||
DbgUtils.logd( BiDiSockWrap.class,
|
||||
"write thread got packet of len %d",
|
||||
packet.length );
|
||||
if ( null == packet ) {
|
||||
if ( null == packet || 0 == packet.length ) {
|
||||
closeSocket();
|
||||
break;
|
||||
}
|
||||
|
@ -126,11 +174,13 @@ public class BiDiSockWrap {
|
|||
= new DataInputStream( mSocket.getInputStream() );
|
||||
while ( mRunThreads ) {
|
||||
short len = inStream.readShort();
|
||||
DbgUtils.logd( BiDiSockWrap.class, "got len: %d", len );
|
||||
byte[] packet = new byte[len];
|
||||
inStream.read( packet );
|
||||
mIface.gotPacket( BiDiSockWrap.this, packet );
|
||||
}
|
||||
} catch( IOException ioe ) {
|
||||
Assert.fail();
|
||||
DbgUtils.logex( ioe );
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
|
|
@ -20,18 +20,17 @@
|
|||
|
||||
package org.eehouse.android.xw4;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import android.app.Activity;
|
||||
import android.net.NetworkInfo;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.net.NetworkInfo;
|
||||
import android.net.wifi.WpsInfo;
|
||||
import android.net.wifi.p2p.WifiP2pConfig;
|
||||
import android.net.wifi.p2p.WifiP2pDevice;
|
||||
import android.net.wifi.p2p.WifiP2pInfo;
|
||||
import android.net.wifi.p2p.WifiP2pDeviceList;
|
||||
import android.net.wifi.p2p.WifiP2pInfo;
|
||||
import android.net.wifi.p2p.WifiP2pManager.ActionListener;
|
||||
import android.net.wifi.p2p.WifiP2pManager.Channel;
|
||||
import android.net.wifi.p2p.WifiP2pManager.ChannelListener;
|
||||
|
@ -42,9 +41,17 @@ import android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceInfo;
|
|||
import android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceRequest;
|
||||
import android.net.wifi.p2p.nsd.WifiP2pUpnpServiceInfo;
|
||||
import android.os.Looper;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
|
@ -52,6 +59,7 @@ public class WifiDirectService {
|
|||
private static final String SERVICE_NAME = "_xwords";
|
||||
private static final String SERVICE_REG_TYPE = "_presence._tcp";
|
||||
private static final boolean WIFI_DIRECT_ENABLED = true;
|
||||
private static final int USE_PORT = 5432;
|
||||
|
||||
private static Context sContext;
|
||||
private static Channel sChannel;
|
||||
|
@ -60,10 +68,18 @@ public class WifiDirectService {
|
|||
private static WFDBroadcastReceiver sReceiver;
|
||||
private static boolean sDiscoveryStarted;
|
||||
private static boolean sEnabled;
|
||||
private static boolean sAmServer;
|
||||
private static Thread sAcceptThread;
|
||||
private static ServerSocket sServerSock;
|
||||
private static BiDiSockWrap.Iface sIface;
|
||||
private static BiDiSockWrap sSocketWrap;
|
||||
private static Set<String> sPendingDevs = new HashSet<String>();
|
||||
public static Activity sActivity;
|
||||
|
||||
public static void activityResumed( Activity activity )
|
||||
{
|
||||
if ( WIFI_DIRECT_ENABLED ) {
|
||||
sActivity = activity;
|
||||
initListeners( activity );
|
||||
activity.registerReceiver( sReceiver, sIntentFilter);
|
||||
DbgUtils.logd( WifiDirectService.class, "activityResumed() done" );
|
||||
|
@ -74,6 +90,7 @@ public class WifiDirectService {
|
|||
public static void activityPaused( Activity activity )
|
||||
{
|
||||
if ( WIFI_DIRECT_ENABLED ) {
|
||||
sActivity = null;
|
||||
activity.unregisterReceiver( sReceiver );
|
||||
DbgUtils.logd( WifiDirectService.class, "activityPaused() done" );
|
||||
}
|
||||
|
@ -84,6 +101,25 @@ public class WifiDirectService {
|
|||
sContext = context;
|
||||
if ( WIFI_DIRECT_ENABLED ) {
|
||||
if ( null == sListener ) {
|
||||
sIface = new BiDiSockWrap.Iface() {
|
||||
public void gotPacket( BiDiSockWrap socket, byte[] bytes )
|
||||
{
|
||||
DbgUtils.logd( WifiDirectService.class, "got packet!!!" );
|
||||
processPacket( socket, bytes );
|
||||
}
|
||||
|
||||
public void connectStateChanged( BiDiSockWrap wrap, boolean nowConnected )
|
||||
{
|
||||
if ( nowConnected ) {
|
||||
try {
|
||||
wrap.send( new JSONObject().put( "cmd", "ping" ) );
|
||||
} catch ( JSONException jse ) {
|
||||
DbgUtils.logex( jse );
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
sListener = new ChannelListener() {
|
||||
@Override
|
||||
public void onChannelDisconnected() {
|
||||
|
@ -131,7 +167,7 @@ public class WifiDirectService {
|
|||
mgr.discoverServices( sChannel, new WDAL("discoverServices") );
|
||||
|
||||
// mgr.discoverPeers( sChannel, sActionListener );
|
||||
DbgUtils.logd( WifiDirectService.class, "called discoverServices" );
|
||||
DbgUtils.logd( WifiDirectService.class, "called mgr.discoverServices" );
|
||||
sDiscoveryStarted = true;
|
||||
}
|
||||
}
|
||||
|
@ -168,16 +204,100 @@ public class WifiDirectService {
|
|||
|
||||
private static void tryConnect( WifiP2pDevice device )
|
||||
{
|
||||
DbgUtils.logd( WifiDirectService.class, "trying to connect to %s",
|
||||
device.toString() );
|
||||
WifiP2pConfig config = new WifiP2pConfig();
|
||||
config.deviceAddress = device.deviceAddress;
|
||||
config.wps.setup = WpsInfo.PBC;
|
||||
final String macAddress = device.deviceAddress;
|
||||
if ( ! sPendingDevs.contains( macAddress ) ) {
|
||||
DbgUtils.logd( WifiDirectService.class, "trying to connect to %s",
|
||||
device.toString() );
|
||||
WifiP2pConfig config = new WifiP2pConfig();
|
||||
config.deviceAddress = device.deviceAddress;
|
||||
config.wps.setup = WpsInfo.PBC;
|
||||
|
||||
WifiP2pManager mgr = (WifiP2pManager)sContext
|
||||
.getSystemService(Context.WIFI_P2P_SERVICE);
|
||||
WifiP2pManager mgr = (WifiP2pManager)sContext
|
||||
.getSystemService(Context.WIFI_P2P_SERVICE);
|
||||
|
||||
mgr.connect( sChannel, config, new WDAL("connect") );
|
||||
mgr.connect( sChannel, config, new ActionListener() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
DbgUtils.logd( getClass(), "onSuccess(): %s", "connect_xx" );
|
||||
sPendingDevs.add( macAddress );
|
||||
}
|
||||
@Override
|
||||
public void onFailure(int reason) {
|
||||
DbgUtils.logd( getClass(), "onFailure(%d): %s", reason, "connect_xx");
|
||||
}
|
||||
} );
|
||||
} else {
|
||||
DbgUtils.logd( WifiDirectService.class, "already connected to %s",
|
||||
macAddress );
|
||||
}
|
||||
}
|
||||
|
||||
private static void connectToOwner( InetAddress addr )
|
||||
{
|
||||
DbgUtils.logd( WifiDirectService.class, "connectToOwner(%s)", addr.toString() );
|
||||
sSocketWrap = new BiDiSockWrap( addr, USE_PORT, sIface ).connect();
|
||||
}
|
||||
|
||||
private static void processPacket( BiDiSockWrap wrap, byte[] bytes )
|
||||
{
|
||||
String asStr = new String(bytes);
|
||||
DbgUtils.logd( WifiDirectService.class, "got string: %s", asStr );
|
||||
try {
|
||||
JSONObject asObj = new JSONObject( asStr );
|
||||
DbgUtils.logd( WifiDirectService.class, "got json: %s", asObj.toString() );
|
||||
final String cmd = asObj.optString( "cmd", "" );
|
||||
sActivity.runOnUiThread( new Runnable() {
|
||||
public void run() {
|
||||
DbgUtils.showf( sActivity, "got cmd: %s", cmd );
|
||||
}
|
||||
} );
|
||||
if ( cmd.equals( "ping" ) ) {
|
||||
try {
|
||||
wrap.send( new JSONObject().put( "cmd", "pong" ) );
|
||||
} catch ( JSONException jse ) {
|
||||
DbgUtils.logex( jse );
|
||||
}
|
||||
}
|
||||
} catch ( JSONException jse ) {
|
||||
DbgUtils.logex( jse );
|
||||
}
|
||||
}
|
||||
|
||||
private static void startAcceptThread()
|
||||
{
|
||||
sAmServer = true;
|
||||
sAcceptThread = new Thread( new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
sServerSock = new ServerSocket( USE_PORT );
|
||||
while ( sAmServer ) {
|
||||
DbgUtils.logd( WifiDirectService.class, "calling accept()" );
|
||||
Socket socket = sServerSock.accept();
|
||||
DbgUtils.logd( WifiDirectService.class, "accept() returned!!" );
|
||||
sSocketWrap = new BiDiSockWrap( socket, sIface );
|
||||
}
|
||||
} catch ( IOException ioe ) {
|
||||
sAmServer = false;
|
||||
DbgUtils.logex( ioe );
|
||||
}
|
||||
}
|
||||
} );
|
||||
sAcceptThread.start();
|
||||
}
|
||||
|
||||
private static void stopAcceptThread()
|
||||
{
|
||||
if ( null != sAcceptThread ) {
|
||||
if ( null != sServerSock ) {
|
||||
try {
|
||||
sServerSock.close();
|
||||
} catch ( IOException ioe ) {
|
||||
DbgUtils.logex( ioe );
|
||||
}
|
||||
sServerSock = null;
|
||||
}
|
||||
sAcceptThread = null;
|
||||
}
|
||||
}
|
||||
|
||||
private static class WFDBroadcastReceiver extends BroadcastReceiver {
|
||||
|
@ -246,16 +366,17 @@ public class WifiDirectService {
|
|||
info.toString(), hostAddress );
|
||||
|
||||
// After the group negotiation, we can determine the group owner.
|
||||
if (info.groupFormed && info.isGroupOwner) {
|
||||
DbgUtils.logd( getClass(), "am group owner" );
|
||||
// Do whatever tasks are specific to the group owner.
|
||||
// One common case is creating a server thread and accepting
|
||||
// incoming connections.
|
||||
} else if (info.groupFormed) {
|
||||
DbgUtils.logd( getClass(), "am NOT group owner" );
|
||||
// The other device acts as the client. In this case,
|
||||
// you'll want to create a client thread that connects to the group
|
||||
// owner.
|
||||
if (info.groupFormed ) {
|
||||
if ( info.isGroupOwner ) {
|
||||
DbgUtils.logd( getClass(), "am group owner" );
|
||||
startAcceptThread();
|
||||
} else {
|
||||
DbgUtils.logd( getClass(), "am NOT group owner" );
|
||||
connectToOwner( info.groupOwnerAddress );
|
||||
// The other device acts as the client. In this case,
|
||||
// you'll want to create a client thread that connects to the group
|
||||
// owner.
|
||||
}
|
||||
} else {
|
||||
Assert.fail();
|
||||
}
|
||||
|
@ -264,12 +385,13 @@ public class WifiDirectService {
|
|||
|
||||
private static class PLL implements WifiP2pManager.PeerListListener {
|
||||
@Override
|
||||
public void onPeersAvailable(WifiP2pDeviceList peerList) {
|
||||
public void onPeersAvailable( WifiP2pDeviceList peerList ) {
|
||||
DbgUtils.logd( getClass(), "got list of %d peers",
|
||||
peerList.getDeviceList().size() );
|
||||
|
||||
for ( WifiP2pDevice device : peerList.getDeviceList() ) {
|
||||
// tryConnect( device );
|
||||
// DbgUtils.logd( getClass(), "not connecting to: %s", device.toString() );
|
||||
tryConnect( device );
|
||||
}
|
||||
// Out with the old, in with the new.
|
||||
// peers.clear();
|
||||
|
|
Loading…
Reference in a new issue