I'm working on an Android Wi-Fi P2p project (also called WiFi direct).
This is how I try to create the group:
public class WiFiDirectBroadcastReceiver extends BroadcastReceiver {
private WifiP2pManager mManager;
private Channel mChannel;
private MainActivity mActivity;
public WiFiDirectBroadcastReceiver(WifiP2pManager p2pManager,
Channel channel, MainActivity mainActivity) {
super();
this.mManager = p2pManager;
this.mChannel = channel;
this.mActivity = mainActivity;
}
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
String state = MainActivity.wifiP2PStateMap.get(intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1));
if (state.equalsIgnoreCase("ENABLED")) {
Log.d(MainActivity.TAG, "P2P state changed to ENABLED ");
mManager.createGroup(mChannel, new WifiP2pManager.ActionListener() {
#Override
public void onSuccess() {
Log.d(MainActivity.TAG, "Group created ");
}
#Override
public void onFailure(int reason) {
Log.d(MainActivity.TAG, "Failed to create Group " + MainActivity.failureMap.get(reason));
}
});
}
}else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)){
//STUB
}else if (WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION.equals(action)){
//STUB
}else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {
//STUB
}else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) {
//STUB
}
}
}
When I scan the available wifi groups using wifi-analyzer I see that my group was created on channel 1, and it is always on channel 1.
Since this channel might be over crowded with other Access points I want to use a different channel.
The problem is that Android's API does not have a visible method to change the channel.
Here I found these questions: Q1, Q2, but they suggest rooting the device which is not an option for me.
When I looked into Android's sources I found that there is a hidden method:
/** #hide */
public void setWifiP2pChannels(Channel c, int lc, int oc, ActionListener listener) {
checkChannel(c);
Bundle p2pChannels = new Bundle();
p2pChannels.putInt("lc", lc);
p2pChannels.putInt("oc", oc);
c.mAsyncChannel.sendMessage(SET_CHANNEL, 0, c.putListener(listener), p2pChannels);
}
Using reflection I tried the following:
Method setWifiP2pChannels = p2pManager.getClass().getMethod("setWifiP2pChannels", WifiP2pManager.Channel.class, int.class, int.class, WifiP2pManager.ActionListener.class);
setWifiP2pChannels.invoke(p2pManager, channel, 0, channel_to_set, new WifiP2pManager.ActionListener() {
#Override
public void onSuccess() {
Log.d(MainActivity.TAG, "Changed channel (" + channel_to_set + ") succeeded");
}
#Override
public void onFailure(int reason) {
Log.d(MainActivity.TAG, "Changed channel (" + channel_to_set + ") failed");
}
});
When channel_to_set was 0 or 1 the actual channel did not change. When channel_to_set to something higher, creating a group returned an error.
Any idea how to solve this?
Thanks
Related
I'm new here. Anyways I've been scratching my head at this issue I have. I created a service that runs WiFiP2pHelper to discover nearby devices and retrieve WifiP2pDnsSdServiceInfo. I tested it on multiple phones, and they seem to work fine. If it works fine, it should return logs like these:
2020-08-12 13:32:23.449 24345-24345/com.example.acts D/WiFi P2P Helper: Service Request Added
2020-08-12 13:32:23.449 24345-24345/com.example.acts D/WiFi P2P Helper: Discover Services Successful
2020-08-12 13:32:23.473 24345-24345/com.example.acts D/WiFi P2P Helper: Local Service Added
Now I made the service to run in the background (even when the application is killed). It seems to work fine on the devices I've tested except any that runs on Android 10. I suspect it's something with Android 10 that causes WiFiP2pManager or WiFi P2P itself not to run in the background. But I'm not entirely sure if it's Android 10 causing it (I only got 2 Android 10 devices that were tested on). It returns the following logs:
2020-08-12 13:33:23.517 24345-24345/com.example.acts D/WiFi P2P Helper: Service Request Added
2020-08-12 13:33:23.517 24345-24345/com.example.acts D/WiFi P2P Helper: Error with P2P 0
2020-08-12 13:33:23.518 24345-24345/com.example.acts D/WiFi P2P Helper: Failed to Add Local Service
2020-08-12 13:33:23.518 24345-24345/com.example.acts E/WiFi P2P Helper: 0
As you can see, "Error with P2P 0" and "Failed to Add Local Service" points to the discoverServices and addLocalService. Below is the code. Sorry to dump it all here. Any help would really be appreciated! Thanks!
public class WiFiP2PHelper extends Service {
WifiP2pManager manager;
WifiP2pManager.Channel channel;
WifiP2pDnsSdServiceRequest serviceRequest;
IntentFilter intentFilter;
String iid;
private String baseServiceName = "ACTS";
private String serviceName = "";
final HashMap<String, String> buddies = new HashMap<String, String>();
final String TAG = "WiFi P2P Helper";
Handler handler = new Handler();
Runnable runnable;
int delay = 15000;
#RequiresApi(api = Build.VERSION_CODES.O)
#Override
public void onCreate() {
super.onCreate();
}
#RequiresApi(api = Build.VERSION_CODES.O)
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
manager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
channel = manager.initialize(this, getMainLooper(), null);
intentFilter = new IntentFilter();
intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
getUser();
startRegistration();
discoverService();
startMyOwnForeground();
return START_STICKY;
}
#RequiresApi(api = Build.VERSION_CODES.O)
private void startMyOwnForeground() {
String NOTIFICATION_CHANNEL_ID = "com.example.acts";
String channelName = "My Background Service";
NotificationChannel chan = new NotificationChannel(NOTIFICATION_CHANNEL_ID, channelName, NotificationManager.IMPORTANCE_NONE);
chan.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
assert manager != null;
manager.createNotificationChannel(chan);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID);
Notification notification = notificationBuilder.setOngoing(true)
.setSmallIcon(R.drawable.ic_launcher_background)
.setContentTitle("Hello World")
.setPriority(NotificationManager.IMPORTANCE_MIN)
.setCategory(Notification.CATEGORY_SERVICE)
.build();
startForeground(1333, notification);
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
private void getUser() {
List<User> users = User.getUser();
int count = users.size();
if (count > 0) {
User loggedInUser = users.get(0);
iid = loggedInUser.Id;
serviceName = baseServiceName + "_" + loggedInUser.Id;
Log.e("User", iid);
} else {
//uId = "User_Unregistered";
serviceName = baseServiceName + "_User_Unregistered";
Log.e("User in else", serviceName);
}
}
public String getWFDMacAddress() {
try {
List<NetworkInterface> interfaces = Collections.list(NetworkInterface.getNetworkInterfaces());
for (NetworkInterface ntwInterface : interfaces) {
if (ntwInterface.getName().equalsIgnoreCase("p2p0")) {
byte[] byteMac = ntwInterface.getHardwareAddress();
if (byteMac == null) {
return null;
}
StringBuilder strBuilder = new StringBuilder();
for (int i = 0; i < byteMac.length; i++) {
strBuilder.append(String.format("%02X:", byteMac[i]));
}
if (strBuilder.length() > 0) {
strBuilder.deleteCharAt(strBuilder.length() - 1);
}
return strBuilder.toString().toLowerCase();
}
}
} catch (Exception e) {
Log.d(TAG, e.getMessage());
}
return null;
}
public int findOpenSocket() throws IOException {
// Initialize a server socket on the next available port.
ServerSocket serverSocket = new ServerSocket(0);
// Store the chosen port.
int port = serverSocket.getLocalPort();
serverSocket.close();
return port;
}
private void startRegistration() {
manager.clearLocalServices(channel, new WifiP2pManager.ActionListener() {
#Override
public void onSuccess() {
Log.e(TAG, "onSuccess: Sucessss");
int port = 3030;
try {
port = findOpenSocket();
} catch (IOException e) {
e.printStackTrace();
}
Map record = new HashMap();
record.put("listenport", String.valueOf(port));
record.put("buddyname", iid);
record.put("available", "visible");
WifiP2pDnsSdServiceInfo serviceInfo =
WifiP2pDnsSdServiceInfo.newInstance(serviceName, "_presence._tcp", record);
manager.addLocalService(channel, serviceInfo, new WifiP2pManager.ActionListener() {
#Override
public void onSuccess() {
Log.d(TAG, "Local Service Added");
}
#Override
public void onFailure(int arg0) {
Log.d(TAG, "Failed to Add Local Service");
Log.e(TAG, String.valueOf(arg0));
}
});
}
#Override
public void onFailure(int arg0) {
Log.d(TAG, "P2P Unsupported");
}
});
}
private void discoverService() {
WifiP2pManager.DnsSdTxtRecordListener txtListener = new WifiP2pManager.DnsSdTxtRecordListener() {
#Override
public void onDnsSdTxtRecordAvailable(
String fullDomain, Map record, WifiP2pDevice device) {
Log.d(TAG, "DnsSdTxtRecord available - " + record.toString());
buddies.put(device.deviceAddress, (String) record.get("buddyname"));
}
};
WifiP2pManager.DnsSdServiceResponseListener servListener = new WifiP2pManager.DnsSdServiceResponseListener() {
#Override
public void onDnsSdServiceAvailable(String instanceName, String registrationType,
WifiP2pDevice resourceType) {
resourceType.deviceName = buddies
.containsKey(resourceType.deviceAddress) ? buddies
.get(resourceType.deviceAddress) : resourceType.deviceName;
String uId = instanceName.replace(baseServiceName + "_", "");
Log.d(TAG, "Received " + uId);
/*Discovered device1 = new Discovered();
device1.discoveredthreeID = uId;
Discovered.insertTransactionToSQLite(device1);*/
}
};
serviceRequest = WifiP2pDnsSdServiceRequest.newInstance();
manager.addServiceRequest(channel,
serviceRequest,
new WifiP2pManager.ActionListener() {
#Override
public void onSuccess() {
Log.d(TAG, "Service Request Added");
}
#Override
public void onFailure(int code) {
Log.d(TAG, "Failed to Add Service Request");
}
});
manager.setDnsSdResponseListeners(channel, servListener, txtListener);
manager.discoverServices(channel, new WifiP2pManager.ActionListener() {
#Override
public void onSuccess() {
Log.d(TAG, "Discover Services Successful");
}
#Override
public void onFailure(int code) {
// Command failed. Check for P2P_UNSUPPORTED, ERROR, or BUSY
if (code == WifiP2pManager.P2P_UNSUPPORTED) {
Log.d(TAG, "P2P isn't supported on this device.");
} else if (code == WifiP2pManager.ERROR) {
Log.d(TAG, "Error with P2P " + code);
} else if (code == WifiP2pManager.BUSY) {
Log.d(TAG, "P2P is Busy " + code);
}
}
});
}
}
Hi everyone who has the same issue as me. I found the solution to this. Basically, Android 10 (API 29) separates location permissions to the normal location permission and background location permission. You'll need to get your application to prompt for background permission (since it's not allowed by default).
Add these to your AndroidManifest.xml file
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
and in my MainActivity onCreate method I added a check to see if the device is on Android 10 (API 29) and if the permissions have already been granted
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
if ((ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) ||
(ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_BACKGROUND_LOCATION) != PackageManager.PERMISSION_GRANTED)) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_BACKGROUND_LOCATION}, 1);
}
} else {
if ((ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED)) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1);
}
}
If anyone else has a better way of implementing permission checks, please share it here. I'd like to learn as well. Thanks!
First time trying to do IP Discovery in Android. I used the http://developer.android.com/training/connect-devices-wirelessly/nsd.html#discover and wrote the code. I am not registering the device, just Discovering Services in the network. When I run the project in emulator or device the onDiscoveryStarted() gets called, but the onServiceFound() is never called. Please find my Code below. Any input is much appreciated. Thanks!
public class MainActivity extends AppCompatActivity {
private Button discoverButton;
Context mContext;
NsdManager mNsdManager;
NsdManager.ResolveListener mResolveListener;
NsdManager.DiscoveryListener mDiscoveryListener;
NsdManager.RegistrationListener mRegistrationListener;
public static final String SERVICE_TYPE = "_http._tcp.";
public static final String TAG = "MyApp_MAIN_CLIENT";
public String mServiceName = "MyApp";
/*
* public static final String SERVICE_TYPE = "_http._tcp.";
public static final String TAG = "NsdHelper";
public String mServiceName = "NsdChat";
* */
NsdServiceInfo mService;
private Handler mUpdateHandler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mNsdManager = (NsdManager) this.getSystemService(Context.NSD_SERVICE);
discoverButton = (Button) findViewById(R.id.netButton);
discoverButton.setOnClickListener(new View.OnClickListener() {
public void onClick(android.view.View v) {
initializeDiscoveryListener();
initializeResolveListener();
discoverServices();
}
});
}
public void discoverServices() {
mNsdManager.discoverServices(
SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, mDiscoveryListener);
}
public void initializeDiscoveryListener() {
// Instantiate a new DiscoveryListener
mDiscoveryListener = new NsdManager.DiscoveryListener() {
// Called as soon as service discovery begins.
#Override
public void onDiscoveryStarted(String regType) {
Log.d(TAG, "Service discovery started");
}
#Override
public void onServiceFound(NsdServiceInfo service) {
// A service was found! Do something with it.
Log.d(TAG, "Service discovery success" + service);
if (!service.getServiceType().equals(SERVICE_TYPE)) {
// Service type is the string containing the protocol and
// transport layer for this service.
Log.d(TAG, "Unknown Service Type: " + service.getServiceType());
} /*else if (service.getServiceName().equals(mServiceName)) {
// The name of the service tells the user what they'd be
// connecting to. It could be "Bob's Chat App".
Log.d(TAG, "Same machine: " + mServiceName);
}
//else if (service.getServiceName().contains("NsdChat")){*/
else{
mNsdManager.resolveService(service, mResolveListener);
}
}
#Override
public void onServiceLost(NsdServiceInfo service) {
// When the network service is no longer available.
// Internal bookkeeping code goes here.
Log.e(TAG, "service lost" + service);
}
#Override
public void onDiscoveryStopped(String serviceType) {
Log.i(TAG, "Discovery stopped: " + serviceType);
}
#Override
public void onStartDiscoveryFailed(String serviceType, int errorCode) {
Log.e(TAG, "Discovery failed: Error code:" + errorCode);
mNsdManager.stopServiceDiscovery(this);
}
#Override
public void onStopDiscoveryFailed(String serviceType, int errorCode) {
Log.e(TAG, "Discovery failed: Error code:" + errorCode);
mNsdManager.stopServiceDiscovery(this);
}
};
}// end of initializeListener()
public void initializeResolveListener() {
mResolveListener = new NsdManager.ResolveListener() {
#Override
public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
Log.e(TAG, "Resolve failed" + errorCode);
}
#Override
public void onServiceResolved(NsdServiceInfo serviceInfo) {
Log.e(TAG, "Resolve Succeeded. " + serviceInfo);
if (serviceInfo.getServiceName().equals(mServiceName)) {
Log.d(TAG, "Same IP.");
return;
}
mService = serviceInfo;
int port = mService.getPort();
InetAddress host = mService.getHost();
Log.d(TAG,host.toString());
}
};
}//end of initializeResolveListener
#Override
protected void onPause() {
super.onPause();
stopDiscovery();
tearDown();
}
#Override
protected void onResume() {
super.onResume();
discoverServices();
}
#Override
protected void onDestroy() {
tearDown();
super.onDestroy();
}
public void stopDiscovery() {
mNsdManager.stopServiceDiscovery(mDiscoveryListener);
}
public void tearDown() {
mNsdManager.unregisterService(mRegistrationListener);
}
}
From NdsManager documentation page:
The API currently supports DNS based service discovery and discovery
is currently limited to a local network over Multicast DNS.
From this Local networking limitations emulator docs page:
Currently, the emulator does not support IGMP or multicast.
Hope this will help you
Probably due to the age of this post, I hope you already found a solution.
If not, my experience is that the Android Emulator (API level 25) does not provide a full network stack and the service discovery through NSD isn't working.
I switched to debugging on a real device (like an Android TV or tablet) and then my whole NSD/Bonjour-like setup was working. The methods of the DiscoveryListener and the ResolveListener were called and an IP and port (in my case) were retrieved.
After some hours working with Android NSD, I discovered that this library does not work with routers that don't support Multicast. While the other answers may are correct, this could also be the cause of your problem. Possible solutions: enable Multicast on your router if possible, or use another network library.
The Network Service Discovery Manager class provides the API to discover services on a network.
This will work when your device is connected to the same WIFI network as that of the device providing the service.
Hope this helps!!
Happy Coding!!
community,
this is my first question, so please tell me if I accidentally don't match some norms or similiar.
I am trying to code an android application that communicates with WiFi direct.
Everything works smooth at this point, but my BroadcastReceiver receives the android.net.wifi.p2p.PEERS_CHANGED action again and again.
public class WifiP2PBroadcastReceiver extends BroadcastReceiver {
private final static String TAG = "WifiP2PBR";
private WifiP2pManager _manager;
private WifiP2pManager.Channel _channel;
private Activity _callbackActivity;
private static ArrayList<WifiBroadcastCallback> _arrayList_callbacks;
public WifiP2PBroadcastReceiver(WifiP2pManager manager, WifiP2pManager.Channel channel, Activity callback) {
_manager = manager;
_channel = channel;
_callbackActivity = callback;
}
/**
* add a callback to the receiver
*
* #param callback
*/
public static void addWifiCallback(WifiBroadcastCallback callback) {
if(!getCallbacksList().contains(callback))
{
getCallbacksList().add(callback);
}
}
public void registerReceiver()
{
Log.d(TAG,"registerReceiver called");
if(_callbackActivity != null) {
_callbackActivity.registerReceiver(this, getIntentFilter());
}
}
public void unregisterReceiver() {
if(_callbackActivity != null) {
_callbackActivity.unregisterReceiver(this);
}
}
#Override
public final void onReceive(Context context, Intent intent) {
Log.d(TAG, "action: "+intent.getAction());
switch(intent.getAction()) {
case WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION:
Log.d(TAG, "state changed action");
break;
case WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION:
Log.d(TAG, "peers changed action");
notifyPeerUpdate();
break;
case WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION:
Log.d(TAG, "wifi p2p connection changed action");
NetworkInfo networkInfo = intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);
Log.d(TAG,"network info available");
break;
case WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION:
Log.d(TAG, "wifi p2p this device changed action");
notifyDeviceUpdate();
WifiP2pDevice thisDevice = intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_DEVICE);
Log.d(TAG,"this device acquired");
break;
}
}
private void notifyPeerUpdate()
{
for(WifiBroadcastCallback c : getCallbacksList())
{
c.onPeersChanged();
}
}
private void notifyDeviceUpdate()
{
for(WifiBroadcastCallback c : getCallbacksList())
{
c.onDeviceChanged();
}
}
/**
* get array list of callbacks
*
* #return
*/
private static ArrayList<WifiBroadcastCallback> getCallbacksList() {
if(_arrayList_callbacks == null) {
_arrayList_callbacks = new ArrayList<WifiBroadcastCallback>();
}
return _arrayList_callbacks;
}
/**
* interface for callbacks
*/
public interface WifiBroadcastCallback {
void onDeviceChanged();
void onPeersChanged();
}
private IntentFilter getIntentFilter()
{
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
return intentFilter;
}
}
this is my BroadcastReceiver code. Everything else works fine and I'm out of ideas, it started out of the nowhere.
That's how it works indeed. Basically, what you should do there, is to call requestPeers with your instance of WifiP2pManager. Then you onPeersAvailable from WifiP2pManager.PeerListListener would be called with the array of peers seen, and there you could then check whether the change is something that you want to report.
reference implementation can be found from my github projects
I've been coding a SIP client using the Android SDK's native SIP libs.
For some reason I cannot get my account to register with the server.
Here are the testing grounds:
Linux Mint 17 XFCE running a Kamailio Server(MySQL and TLS enabled).
Linux Mint 17 Cinnamon running Android Studio (0.8.6).
Asus Google Nexus 7 (2nd gen).
All of the above are on 192.168.1.xxx
The server and account info has been tested with a working SipClient (ZoIPer). The port 5060 has been tested with a telnet command from the coding machine to the server. The client I'm building has also been tested with a third-party SIP service on a distant server (with identical results). Is there any idea how to make it works?
MainActivity
public class MainActivity extends Activity {
public CommsController cc;
public IncomingCallReceiver callReceiver;
public Context ctx = this;
Button callButton;
EditText phoneTextBox;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
cc = new CommsController();
cc.createManager(this);
cc.createProfile("linasAndroid","192.168.1.140","android001");
callReceiver = new IncomingCallReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction("util.Controller.IncomingCallReceiver");
this.registerReceiver(callReceiver, filter);
cc.openProfile(this);
try {
System.out.println("+++ IS API SUPPORTED: " + cc.getManager().isApiSupported(this));
System.out.println("+++ IS VOIP SUPORTED: " + cc.getManager().isVoipSupported(this));
System.out.println("+++ MANAGER INSTANCE: " + cc.getManager().toString());
boolean isOpened = cc.getManager().isOpened(cc.getMe().getUriString());
System.out.println("+++ IS OPENED: "+isOpened);
if(isOpened){
cc.getManager().register(cc.getMe(), 30000, cc.getSrl());
cc.createRegistrationListener();
}
}catch(SipException sipex){
System.out.println(sipex.getCause()+", "+ sipex.getMessage());
//sipex.printStackTrace();
}
callButton = (Button) findViewById(R.id.callButton);
phoneTextBox = (EditText) findViewById(R.id.phoneTextBox);
callButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
cc.makeCall("sip:"+phoneTextBox.getText()+"#192.168.1.140");
}
});
}
#Override
protected void onDestroy() {
super.onDestroy();
this.unregisterReceiver(callReceiver);
}
public Context getContext(){return ctx;}
public CommsController getCc() {
return cc;
}
CommsController
public class CommsController {
public String sipAddress = null;
public SipManager manager = null;
public SipProfile me = null;
public SipAudioCall call = null;
public Context ctx;
private PendingIntent pendingIntent;
public SipRegistrationListener srl;
private static final int CALL_ADDRESS = 1;
private static final int SET_AUTH_INFO = 2;
private static final int UPDATE_SETTINGS_DIALOG = 3;
private static final int HANG_UP = 4;
SipAudioCall.Listener listener = new SipAudioCall.Listener(){
#Override
public void onCallEstablished(SipAudioCall call) {
call.startAudio();
call.setSpeakerMode(true);
call.toggleMute();
}
#Override
public void onCallEnded(SipAudioCall call) {
// Do something.
}
};
public void createManager(Context context) {
if (manager == null) {
manager = SipManager.newInstance(context);
}
}
public boolean createProfile(String uname, String domain, String pass){
try {
SipProfile.Builder builder = new SipProfile.Builder(uname, domain);
builder.setPassword(pass);
builder.setProtocol("TCP");
builder.setPort(5060);
me = builder.build();
setMe(me);
System.out.println("+++ User Profile = CREATED");
return true;
} catch (ParseException e) {
e.printStackTrace();
System.out.println("+++ User Profile = FAILED");
return false;
}
}
public void openProfile(Context context){
try {
System.out.println("+++ ATTEMPTING TO OPEN PROFILE: " + me.getUriString());
Intent intent = new Intent();
intent.setAction("util.Controller.IncomingCallReceiver");
pendingIntent = PendingIntent.getBroadcast(context, 0, intent, Intent.FILL_IN_DATA);
manager.open(getMe(), pendingIntent, null);
System.out.println("+++ IS OPEN IN CC: " +manager.isOpened(getMe().getUriString()));
} catch (SipException e) {
e.printStackTrace();
System.out.println("+++ Profile Registration = FAILED");
}
}
public void createRegistrationListener(){
System.out.println("+++ CREATING REG LISTENER...");
srl = new SipRegistrationListener() {
#Override
public void onRegistering(String localProfileUri) {
System.out.println("+++ REGISTERING...");
}
#Override
public void onRegistrationDone(String localProfileUri, long expiryTime) {
System.out.println("+++ READY");
}
#Override
public void onRegistrationFailed(String localProfileUri, int errorCode, String errorMessage) {
System.out.println("+++ REGISTRATION FAILED. CHECK SETTINGS. ERROR: "+ errorCode + " MESSAGE: " +errorMessage);
}
};
}
public SipRegistrationListener getSrl(){
return srl;
}
public void closeProfile(SipProfile toClose){
if(manager==null){
return;
}
try {
if (manager != null) {
manager.close(toClose.getUriString());
System.out.println("PROFILE CLOSED: " +toClose.getUriString());
}
} catch (Exception ee) {
ee.printStackTrace();
System.out.println("FAILED TO CLOSE LOCAL PROFILE: "+ toClose.toString());
}
}
public void logOut(){
try {
System.out.println("+++ DEREGISTERING...");
manager.close(me.getUriString());
}catch(SipException se){
System.out.println("+++ DEREGISTRATION FAILED");
se.printStackTrace();
}
}
public void makeCall(String toCall){
try {
call = manager.makeAudioCall(me.getUriString(), toCall, listener, 30);
} catch (SipException e) {
e.printStackTrace();
}
}
//Getters and setters...
Output (LogCat)
09-09 16:46:53.709 22783-22783/com.inlusion.inlusip I/Adreno-EGL﹕ <qeglDrvAPI_eglInitialize:320>: EGL 1.4 QUALCOMM Build: I0404c4692afb8623f95c43aeb6d5e13ed4b30ddbDate: 11/06/13
09-09 16:46:53.739 22783-22783/com.inlusion.inlusip D/OpenGLRenderer﹕ Enabling debug mode 0
09-09 16:46:55.841 22783-22783/com.inlusion.inlusip I/System.out﹕ +++ User Profile = CREATED
09-09 16:46:55.841 22783-22783/com.inlusion.inlusip I/System.out﹕ +++ ATTEMPTING TO OPEN PROFILE: sip:linasAndroid#192.168.1.140;transport=tcp
09-09 16:46:55.921 22783-22783/com.inlusion.inlusip D/dalvikvm﹕ GC_FOR_ALLOC freed 316K, 4% free 9182K/9532K, paused 19ms, total 19ms
09-09 16:46:55.941 22783-22783/com.inlusion.inlusip I/System.out﹕ +++ IS OPEN IN CC: false
09-09 16:46:55.941 22783-22783/com.inlusion.inlusip I/System.out﹕ +++ IS API SUPPORTED: true
09-09 16:46:55.941 22783-22783/com.inlusion.inlusip I/System.out﹕ +++ IS VOIP SUPORTED: true
09-09 16:46:55.941 22783-22783/com.inlusion.inlusip I/System.out﹕ +++ MANAGER INSTANCE: android.net.sip.SipManager#4256de78
09-09 16:46:55.941 22783-22783/com.inlusion.inlusip I/System.out﹕ +++ IS OPENED: false
EDIT:
After messing around with pjsip, mjsip and jain-sip, I desparately made one last attempt to rewrite this using the SDKs sip stack, in a more structured manner, separating the methods into classes that handle talking to the registrar, handling a call etc., you know- standard MVC layout.
After two weeks of repackaging third-party libraries and trying to figure out the NDK...
This bastard worked. Goes to show - structure your code right!
EDIT 2:
The issue is back after removing the app from the device and running it again. Once more- no idea what's causing it. Had gotten to the point where I could register, unregister and make two way audio calls until it started happening again.
EDIT 3:
It seems the problem goes away when the device is rebooted. Starting to think it's either an unclosed socket or a previously opened profile. Any suggestions?
EDIT 4:
Bug also occurs when another VoIP SIP application (with the pjsip OR mjsip stack) is present and connected to the server with the same account credentials.
I am trying to connect 2 Android devices through Wi-fi Direct.
In my application I am hard coding the MAC address of the other device and calling the method connect. I am assuming that Wi-Fi Direct is on in both the devices. Here is the code I am using:
package com.abc;
import android.app.Activity;
import android.content.Context;
import android.content.IntentFilter;
import android.net.wifi.WpsInfo;
import android.net.wifi.p2p.WifiP2pConfig;
import android.net.wifi.p2p.WifiP2pManager;
import android.net.wifi.p2p.WifiP2pManager.Channel;
import android.os.Bundle;
import android.widget.Toast;
public class WiFiDirectActivity extends Activity {
/** Called when the activity is first created. */
protected WifiP2pManager manager;
protected Channel channel;
public WifiP2pConfig config ;
protected final IntentFilter intentFilter = new IntentFilter();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
intentFilter.addAction (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
intentFilter
.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
manager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
channel = manager.initialize(this, this.getMainLooper(), null);
config = new WifiP2pConfig();
config.deviceAddress = "78:d6:f0:ab:d9:da";
config.groupOwnerIntent = 0;
config.wps.setup = WpsInfo.PBC;
manager.connect(channel, config, new WifiP2pManager.ActionListener(){
#Override
public void onSuccess() {
Toast.makeText(getApplicationContext(), "success", Toast.LENGTH_LONG);
}
#Override
public void onFailure(int reason) {
Toast.makeText(getApplicationContext(), "Failed", Toast.LENGTH_LONG);
}
});
}
}
but it is not connecting. What is wrong with my implementation?
I have a similar code working, the main differences are:
I get the device address calling before to discovery peers (If you do that then you have to add WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION to intent filter group)
I don't set the config.groupOwnerIntent
WifiP2pConfig config = new WifiP2pConfig();
config.deviceAddress = this.address;
config.wps.setup = WpsInfo.PBC;
register a BroadcastReceiver in onResume() and override it. remember to unregister it in onPause()
private class WiFiDirectBroadcastReceiver extends android.content.BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
//TODO
} else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
//TODO
} else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {
//TODO
} else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) {
//TODO
}
}
}
then try to call discoverPeers() first
mWifiP2pManager.discoverPeers(Channel mChannel, ActionListener mActionListener);
if discoverPeers() does find peers, action WIFI_P2P_PEERS_CHANGED_ACTION will be triggered.
we can call requestPeers() in WIFI_P2P_PEERS_CHANGED_ACTION in the BroadcastReceiver
mWifiP2pManager.requestPeers(Channel mChannel, WifiP2pManager.PeerListListener);
so our BroadcastReceiver now looks like this
private class WiFiDirectBroadcastReceiver extends android.content.BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
//TODO
} else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
mWifiP2pManager.requestPeers(mChannel , pl);
} else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {
//TODO
} else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) {
//TODO
}
}
}
to implement WifiP2pManager.PeerListListener, you need to override onPeersAvailable(WifiP2pDeviceList peers)
in onPeersAvailable(), the parameter wifiP2pDeviceList means the peers you discovered
we need a UI object to let us choose which device to connect, so I use spinner here.
also you can use listView or something else.
private List<WifiP2pDevice> mPeers = new ArrayList<WifiP2pDevice>();
spinnerAdapter = new WiFiPeerListAdapter(this, R.layout.row_devices, mPeers);
...
#Override
public void onPeersAvailable(WifiP2pDeviceList wifiP2pDeviceList) {
mPeers.clear();
mPeers.addAll(wifiP2pDeviceList.getDeviceList());
spinnerAdapter.notifyDataSetChanged();
}
finally we can connect to a device
WifiP2pDevice device = spinnerAdapter.getItem((int) mSpinner.getSelectedItemId());
WifiP2pConfig config = new WifiP2pConfig();
config.deviceAddress = device.deviceAddress;
config.wps.setup = WpsInfo.PBC;
mWifiP2pManager.connect(mChannel, config, mActionListener);
after two device connected, BroadcastReceiver action WIFI_P2P_CONNECTION_CHANGED_ACTION will be triggered. so we can do something here.
our BroadcastReceiver now looks like
private class WiFiDirectBroadcastReceiver extends android.content.BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
//TODO
} else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
mWifiP2pManager.requestPeers(mChannel , pl);
} else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {
NetworkInfo networkInfo = intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);
if (networkInfo != null) {
Log.d(TAG,networkInfo.toString());
if (networkInfo.isConnected()) {
mWifiP2pManager.requestConnectionInfo(mChannel, WifiP2pManager.ConnectionInfoListener);
}
}
} else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) {
//TODO
}
}
}
btw, the log in action WIFI_P2P_CONNECTION_CHANGED_ACTION will get something like this
NetworkInfo: type: WIFI_P2P[], state: UNKNOWN/IDLE, reason: (unspecified), extra: (none), roaming: false, failover: false, isAvailable: true, simId: 0
now we need to implement WifiP2pManager.ConnectionInfoListener and override its abstract method onConnectionInfoAvailable(WifiP2pInfo info) for requestConnectionInfo()
private WifiP2pInfo p2pInfo;
#Override
public void onConnectionInfoAvailable(final WifiP2pInfo info) {
p2pInfo = info;
mWifiP2pManager.requestGroupInfo(mChannel, WifiP2pManager.GroupInfoListener);
}
again we need to implement WifiP2pManager.GroupInfoListener and override onGroupInfoAvailable(WifiP2pGroup group)
#Override
public void onGroupInfoAvailable(WifiP2pGroup wifiP2pGroup) {
String log;
if(wifiP2pGroup.isGroupOwner()) {
log = "I am GO";
}else{
log = "I am not GO";
}
Log.d(TAG, log);
}
now we almost got every info about these two devices
enjoy it